xitdb 0.1.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/.claude/settings.local.json +9 -0
- package/README.md +403 -0
- package/bun.lock +24 -0
- package/bunfig.toml +1 -0
- package/dist/index.js +3701 -0
- package/example/README.md +46 -0
- package/example/dump.ts +201 -0
- package/package.json +17 -0
- package/src/core-buffered-file.ts +226 -0
- package/src/core-file.ts +137 -0
- package/src/core-memory.ts +179 -0
- package/src/core.ts +25 -0
- package/src/database.ts +2232 -0
- package/src/exceptions.ts +31 -0
- package/src/hasher.ts +52 -0
- package/src/index.ts +110 -0
- package/src/read-array-list.ts +45 -0
- package/src/read-counted-hash-map.ts +28 -0
- package/src/read-counted-hash-set.ts +28 -0
- package/src/read-cursor.ts +546 -0
- package/src/read-hash-map.ts +117 -0
- package/src/read-hash-set.ts +70 -0
- package/src/read-linked-array-list.ts +45 -0
- package/src/slot-pointer.ts +15 -0
- package/src/slot.ts +51 -0
- package/src/slotted.ts +5 -0
- package/src/tag.ts +23 -0
- package/src/write-array-list.ts +65 -0
- package/src/write-counted-hash-map.ts +31 -0
- package/src/write-counted-hash-set.ts +31 -0
- package/src/write-cursor.ts +166 -0
- package/src/write-hash-map.ts +129 -0
- package/src/write-hash-set.ts +86 -0
- package/src/write-linked-array-list.ts +80 -0
- package/src/writeable-data.ts +67 -0
- package/tests/database.test.ts +2519 -0
- package/tests/fixtures/test.db +0 -0
- package/tsconfig.json +17 -0
package/dist/index.js
ADDED
|
@@ -0,0 +1,3701 @@
|
|
|
1
|
+
// @bun
|
|
2
|
+
var __defProp = Object.defineProperty;
|
|
3
|
+
var __export = (target, all) => {
|
|
4
|
+
for (var name in all)
|
|
5
|
+
__defProp(target, name, {
|
|
6
|
+
get: all[name],
|
|
7
|
+
enumerable: true,
|
|
8
|
+
configurable: true,
|
|
9
|
+
set: (newValue) => all[name] = () => newValue
|
|
10
|
+
});
|
|
11
|
+
};
|
|
12
|
+
var __esm = (fn, res) => () => (fn && (res = fn(fn = 0)), res);
|
|
13
|
+
|
|
14
|
+
// src/tag.ts
|
|
15
|
+
function tagValueOf(n) {
|
|
16
|
+
if (n < 0 || n > 13) {
|
|
17
|
+
throw new Error(`Invalid tag value: ${n}`);
|
|
18
|
+
}
|
|
19
|
+
return n;
|
|
20
|
+
}
|
|
21
|
+
var Tag;
|
|
22
|
+
var init_tag = __esm(() => {
|
|
23
|
+
((Tag2) => {
|
|
24
|
+
Tag2[Tag2["NONE"] = 0] = "NONE";
|
|
25
|
+
Tag2[Tag2["INDEX"] = 1] = "INDEX";
|
|
26
|
+
Tag2[Tag2["ARRAY_LIST"] = 2] = "ARRAY_LIST";
|
|
27
|
+
Tag2[Tag2["LINKED_ARRAY_LIST"] = 3] = "LINKED_ARRAY_LIST";
|
|
28
|
+
Tag2[Tag2["HASH_MAP"] = 4] = "HASH_MAP";
|
|
29
|
+
Tag2[Tag2["KV_PAIR"] = 5] = "KV_PAIR";
|
|
30
|
+
Tag2[Tag2["BYTES"] = 6] = "BYTES";
|
|
31
|
+
Tag2[Tag2["SHORT_BYTES"] = 7] = "SHORT_BYTES";
|
|
32
|
+
Tag2[Tag2["UINT"] = 8] = "UINT";
|
|
33
|
+
Tag2[Tag2["INT"] = 9] = "INT";
|
|
34
|
+
Tag2[Tag2["FLOAT"] = 10] = "FLOAT";
|
|
35
|
+
Tag2[Tag2["HASH_SET"] = 11] = "HASH_SET";
|
|
36
|
+
Tag2[Tag2["COUNTED_HASH_MAP"] = 12] = "COUNTED_HASH_MAP";
|
|
37
|
+
Tag2[Tag2["COUNTED_HASH_SET"] = 13] = "COUNTED_HASH_SET";
|
|
38
|
+
})(Tag ||= {});
|
|
39
|
+
});
|
|
40
|
+
|
|
41
|
+
// src/slot.ts
|
|
42
|
+
class Slot {
|
|
43
|
+
static LENGTH = 9;
|
|
44
|
+
value;
|
|
45
|
+
tag;
|
|
46
|
+
full;
|
|
47
|
+
constructor(value = 0n, tag = 0 /* NONE */, full = false) {
|
|
48
|
+
this.value = value;
|
|
49
|
+
this.tag = tag;
|
|
50
|
+
this.full = full;
|
|
51
|
+
}
|
|
52
|
+
withTag(tag) {
|
|
53
|
+
return new Slot(this.value, tag, this.full);
|
|
54
|
+
}
|
|
55
|
+
withFull(full) {
|
|
56
|
+
return new Slot(this.value, this.tag, full);
|
|
57
|
+
}
|
|
58
|
+
empty() {
|
|
59
|
+
return this.tag === 0 /* NONE */ && !this.full;
|
|
60
|
+
}
|
|
61
|
+
toBytes() {
|
|
62
|
+
const buffer = new ArrayBuffer(Slot.LENGTH);
|
|
63
|
+
const view = new DataView(buffer);
|
|
64
|
+
let tagInt = this.full ? 128 : 0;
|
|
65
|
+
tagInt = tagInt | this.tag;
|
|
66
|
+
view.setUint8(0, tagInt);
|
|
67
|
+
view.setBigInt64(1, this.value, false);
|
|
68
|
+
return new Uint8Array(buffer);
|
|
69
|
+
}
|
|
70
|
+
static fromBytes(bytes) {
|
|
71
|
+
const view = new DataView(bytes.buffer, bytes.byteOffset, bytes.byteLength);
|
|
72
|
+
const tagByte = view.getUint8(0);
|
|
73
|
+
const full = (tagByte & 128) !== 0;
|
|
74
|
+
const tag = tagValueOf(tagByte & 127);
|
|
75
|
+
const value = view.getBigInt64(1, false);
|
|
76
|
+
return new Slot(value, tag, full);
|
|
77
|
+
}
|
|
78
|
+
equals(other) {
|
|
79
|
+
return this.value === other.value && this.tag === other.tag && this.full === other.full;
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
var init_slot = __esm(() => {
|
|
83
|
+
init_tag();
|
|
84
|
+
});
|
|
85
|
+
|
|
86
|
+
// src/slot-pointer.ts
|
|
87
|
+
class SlotPointer {
|
|
88
|
+
position;
|
|
89
|
+
slot;
|
|
90
|
+
constructor(position, slot) {
|
|
91
|
+
this.position = position;
|
|
92
|
+
this.slot = slot;
|
|
93
|
+
}
|
|
94
|
+
withSlot(slot) {
|
|
95
|
+
return new SlotPointer(this.position, slot);
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
// src/exceptions.ts
|
|
100
|
+
var DatabaseException, NotImplementedException, UnreachableException, InvalidDatabaseException, InvalidVersionException, InvalidHashSizeException, KeyNotFoundException, WriteNotAllowedException, UnexpectedTagException, CursorNotWriteableException, ExpectedTxStartException, KeyOffsetExceededException, PathPartMustBeAtEndException, StreamTooLongException, EndOfStreamException, InvalidOffsetException, InvalidTopLevelTypeException, ExpectedUnsignedLongException, NoAvailableSlotsException, MustSetNewSlotsToFullException, EmptySlotException, ExpectedRootNodeException, InvalidFormatTagSizeException, UnexpectedWriterPositionException, MaxShiftExceededException;
|
|
101
|
+
var init_exceptions = __esm(() => {
|
|
102
|
+
DatabaseException = class DatabaseException extends Error {
|
|
103
|
+
constructor(message) {
|
|
104
|
+
super(message);
|
|
105
|
+
this.name = this.constructor.name;
|
|
106
|
+
}
|
|
107
|
+
};
|
|
108
|
+
NotImplementedException = class NotImplementedException extends DatabaseException {
|
|
109
|
+
};
|
|
110
|
+
UnreachableException = class UnreachableException extends DatabaseException {
|
|
111
|
+
};
|
|
112
|
+
InvalidDatabaseException = class InvalidDatabaseException extends DatabaseException {
|
|
113
|
+
};
|
|
114
|
+
InvalidVersionException = class InvalidVersionException extends DatabaseException {
|
|
115
|
+
};
|
|
116
|
+
InvalidHashSizeException = class InvalidHashSizeException extends DatabaseException {
|
|
117
|
+
};
|
|
118
|
+
KeyNotFoundException = class KeyNotFoundException extends DatabaseException {
|
|
119
|
+
};
|
|
120
|
+
WriteNotAllowedException = class WriteNotAllowedException extends DatabaseException {
|
|
121
|
+
};
|
|
122
|
+
UnexpectedTagException = class UnexpectedTagException extends DatabaseException {
|
|
123
|
+
};
|
|
124
|
+
CursorNotWriteableException = class CursorNotWriteableException extends DatabaseException {
|
|
125
|
+
};
|
|
126
|
+
ExpectedTxStartException = class ExpectedTxStartException extends DatabaseException {
|
|
127
|
+
};
|
|
128
|
+
KeyOffsetExceededException = class KeyOffsetExceededException extends DatabaseException {
|
|
129
|
+
};
|
|
130
|
+
PathPartMustBeAtEndException = class PathPartMustBeAtEndException extends DatabaseException {
|
|
131
|
+
};
|
|
132
|
+
StreamTooLongException = class StreamTooLongException extends DatabaseException {
|
|
133
|
+
};
|
|
134
|
+
EndOfStreamException = class EndOfStreamException extends DatabaseException {
|
|
135
|
+
};
|
|
136
|
+
InvalidOffsetException = class InvalidOffsetException extends DatabaseException {
|
|
137
|
+
};
|
|
138
|
+
InvalidTopLevelTypeException = class InvalidTopLevelTypeException extends DatabaseException {
|
|
139
|
+
};
|
|
140
|
+
ExpectedUnsignedLongException = class ExpectedUnsignedLongException extends DatabaseException {
|
|
141
|
+
};
|
|
142
|
+
NoAvailableSlotsException = class NoAvailableSlotsException extends DatabaseException {
|
|
143
|
+
};
|
|
144
|
+
MustSetNewSlotsToFullException = class MustSetNewSlotsToFullException extends DatabaseException {
|
|
145
|
+
};
|
|
146
|
+
EmptySlotException = class EmptySlotException extends DatabaseException {
|
|
147
|
+
};
|
|
148
|
+
ExpectedRootNodeException = class ExpectedRootNodeException extends DatabaseException {
|
|
149
|
+
};
|
|
150
|
+
InvalidFormatTagSizeException = class InvalidFormatTagSizeException extends DatabaseException {
|
|
151
|
+
};
|
|
152
|
+
UnexpectedWriterPositionException = class UnexpectedWriterPositionException extends DatabaseException {
|
|
153
|
+
};
|
|
154
|
+
MaxShiftExceededException = class MaxShiftExceededException extends DatabaseException {
|
|
155
|
+
};
|
|
156
|
+
});
|
|
157
|
+
|
|
158
|
+
// src/writeable-data.ts
|
|
159
|
+
class Uint {
|
|
160
|
+
value;
|
|
161
|
+
constructor(value) {
|
|
162
|
+
if (value < 0n) {
|
|
163
|
+
throw new Error("Uint must not be negative");
|
|
164
|
+
}
|
|
165
|
+
this.value = value;
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
class Int {
|
|
170
|
+
value;
|
|
171
|
+
constructor(value) {
|
|
172
|
+
this.value = value;
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
class Float {
|
|
177
|
+
value;
|
|
178
|
+
constructor(value) {
|
|
179
|
+
this.value = value;
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
class Bytes {
|
|
184
|
+
value;
|
|
185
|
+
formatTag;
|
|
186
|
+
constructor(value, formatTag) {
|
|
187
|
+
if (typeof value === "string") {
|
|
188
|
+
this.value = new TextEncoder().encode(value);
|
|
189
|
+
} else {
|
|
190
|
+
this.value = value;
|
|
191
|
+
}
|
|
192
|
+
if (formatTag === undefined || formatTag === null) {
|
|
193
|
+
this.formatTag = null;
|
|
194
|
+
} else if (typeof formatTag === "string") {
|
|
195
|
+
const encoded = new TextEncoder().encode(formatTag);
|
|
196
|
+
if (encoded.length !== 2) {
|
|
197
|
+
throw new InvalidFormatTagSizeException;
|
|
198
|
+
}
|
|
199
|
+
this.formatTag = encoded;
|
|
200
|
+
} else {
|
|
201
|
+
if (formatTag.length !== 2) {
|
|
202
|
+
throw new InvalidFormatTagSizeException;
|
|
203
|
+
}
|
|
204
|
+
this.formatTag = formatTag;
|
|
205
|
+
}
|
|
206
|
+
}
|
|
207
|
+
isShort() {
|
|
208
|
+
const totalSize = this.formatTag !== null ? 6 : 8;
|
|
209
|
+
if (this.value.length > totalSize)
|
|
210
|
+
return false;
|
|
211
|
+
for (const b of this.value) {
|
|
212
|
+
if (b === 0)
|
|
213
|
+
return false;
|
|
214
|
+
}
|
|
215
|
+
return true;
|
|
216
|
+
}
|
|
217
|
+
}
|
|
218
|
+
var init_writeable_data = __esm(() => {
|
|
219
|
+
init_exceptions();
|
|
220
|
+
});
|
|
221
|
+
|
|
222
|
+
// src/read-cursor.ts
|
|
223
|
+
class KeyValuePairCursor {
|
|
224
|
+
valueCursor;
|
|
225
|
+
keyCursor;
|
|
226
|
+
hash;
|
|
227
|
+
constructor(valueCursor, keyCursor, hash) {
|
|
228
|
+
this.valueCursor = valueCursor;
|
|
229
|
+
this.keyCursor = keyCursor;
|
|
230
|
+
this.hash = hash;
|
|
231
|
+
}
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
class Reader {
|
|
235
|
+
parent;
|
|
236
|
+
size;
|
|
237
|
+
startPosition;
|
|
238
|
+
relativePosition;
|
|
239
|
+
constructor(parent, size, startPosition, relativePosition) {
|
|
240
|
+
this.parent = parent;
|
|
241
|
+
this.size = size;
|
|
242
|
+
this.startPosition = startPosition;
|
|
243
|
+
this.relativePosition = relativePosition;
|
|
244
|
+
}
|
|
245
|
+
async read(buffer) {
|
|
246
|
+
if (this.size < this.relativePosition)
|
|
247
|
+
throw new EndOfStreamException;
|
|
248
|
+
await this.parent.db.core.seek(this.startPosition + this.relativePosition);
|
|
249
|
+
const readSize = Math.min(buffer.length, Number(this.size - this.relativePosition));
|
|
250
|
+
if (readSize === 0)
|
|
251
|
+
return -1;
|
|
252
|
+
const reader = this.parent.db.core.reader();
|
|
253
|
+
const tempBuffer = new Uint8Array(readSize);
|
|
254
|
+
await reader.readFully(tempBuffer);
|
|
255
|
+
buffer.set(tempBuffer);
|
|
256
|
+
this.relativePosition += BigInt(readSize);
|
|
257
|
+
return readSize;
|
|
258
|
+
}
|
|
259
|
+
async readFully(buffer) {
|
|
260
|
+
if (this.size < this.relativePosition || this.size - this.relativePosition < BigInt(buffer.length)) {
|
|
261
|
+
throw new EndOfStreamException;
|
|
262
|
+
}
|
|
263
|
+
await this.parent.db.core.seek(this.startPosition + this.relativePosition);
|
|
264
|
+
const reader = this.parent.db.core.reader();
|
|
265
|
+
await reader.readFully(buffer);
|
|
266
|
+
this.relativePosition += BigInt(buffer.length);
|
|
267
|
+
}
|
|
268
|
+
async readByte() {
|
|
269
|
+
const bytes = new Uint8Array(1);
|
|
270
|
+
await this.readFully(bytes);
|
|
271
|
+
return bytes[0];
|
|
272
|
+
}
|
|
273
|
+
async readShort() {
|
|
274
|
+
const readSize = 2;
|
|
275
|
+
const bytes = new Uint8Array(readSize);
|
|
276
|
+
await this.readFully(bytes);
|
|
277
|
+
const view = new DataView(bytes.buffer, bytes.byteOffset, bytes.byteLength);
|
|
278
|
+
return view.getInt16(0, false);
|
|
279
|
+
}
|
|
280
|
+
async readInt() {
|
|
281
|
+
const readSize = 4;
|
|
282
|
+
const bytes = new Uint8Array(readSize);
|
|
283
|
+
await this.readFully(bytes);
|
|
284
|
+
const view = new DataView(bytes.buffer, bytes.byteOffset, bytes.byteLength);
|
|
285
|
+
return view.getInt32(0, false);
|
|
286
|
+
}
|
|
287
|
+
async readLong() {
|
|
288
|
+
const readSize = 8;
|
|
289
|
+
const bytes = new Uint8Array(readSize);
|
|
290
|
+
await this.readFully(bytes);
|
|
291
|
+
const view = new DataView(bytes.buffer, bytes.byteOffset, bytes.byteLength);
|
|
292
|
+
return view.getBigInt64(0, false);
|
|
293
|
+
}
|
|
294
|
+
seek(position) {
|
|
295
|
+
if (position > this.size) {
|
|
296
|
+
throw new InvalidOffsetException;
|
|
297
|
+
}
|
|
298
|
+
this.relativePosition = position;
|
|
299
|
+
}
|
|
300
|
+
}
|
|
301
|
+
|
|
302
|
+
class IteratorLevel {
|
|
303
|
+
position;
|
|
304
|
+
block;
|
|
305
|
+
index;
|
|
306
|
+
constructor(position, block, index) {
|
|
307
|
+
this.position = position;
|
|
308
|
+
this.block = block;
|
|
309
|
+
this.index = index;
|
|
310
|
+
}
|
|
311
|
+
}
|
|
312
|
+
|
|
313
|
+
class CursorIterator {
|
|
314
|
+
cursor;
|
|
315
|
+
size = 0n;
|
|
316
|
+
index = 0n;
|
|
317
|
+
stack = [];
|
|
318
|
+
nextCursorMaybe = null;
|
|
319
|
+
initialized = false;
|
|
320
|
+
constructor(cursor) {
|
|
321
|
+
this.cursor = cursor;
|
|
322
|
+
}
|
|
323
|
+
async init() {
|
|
324
|
+
if (this.initialized)
|
|
325
|
+
return;
|
|
326
|
+
this.initialized = true;
|
|
327
|
+
switch (this.cursor.slotPtr.slot.tag) {
|
|
328
|
+
case 0 /* NONE */:
|
|
329
|
+
this.size = 0n;
|
|
330
|
+
this.index = 0n;
|
|
331
|
+
this.stack = [];
|
|
332
|
+
break;
|
|
333
|
+
case 2 /* ARRAY_LIST */: {
|
|
334
|
+
const position = this.cursor.slotPtr.slot.value;
|
|
335
|
+
await this.cursor.db.core.seek(position);
|
|
336
|
+
const reader = this.cursor.db.core.reader();
|
|
337
|
+
const headerBytes = new Uint8Array(ArrayListHeader.LENGTH);
|
|
338
|
+
await reader.readFully(headerBytes);
|
|
339
|
+
const header = ArrayListHeader.fromBytes(headerBytes);
|
|
340
|
+
this.size = await this.cursor.count();
|
|
341
|
+
this.index = 0n;
|
|
342
|
+
this.stack = await this.initStack(this.cursor, header.ptr, INDEX_BLOCK_SIZE);
|
|
343
|
+
break;
|
|
344
|
+
}
|
|
345
|
+
case 3 /* LINKED_ARRAY_LIST */: {
|
|
346
|
+
const position = this.cursor.slotPtr.slot.value;
|
|
347
|
+
await this.cursor.db.core.seek(position);
|
|
348
|
+
const reader = this.cursor.db.core.reader();
|
|
349
|
+
const headerBytes = new Uint8Array(LinkedArrayListHeader.LENGTH);
|
|
350
|
+
await reader.readFully(headerBytes);
|
|
351
|
+
const header = LinkedArrayListHeader.fromBytes(headerBytes);
|
|
352
|
+
this.size = await this.cursor.count();
|
|
353
|
+
this.index = 0n;
|
|
354
|
+
this.stack = await this.initStack(this.cursor, header.ptr, LINKED_ARRAY_LIST_INDEX_BLOCK_SIZE);
|
|
355
|
+
break;
|
|
356
|
+
}
|
|
357
|
+
case 4 /* HASH_MAP */:
|
|
358
|
+
case 11 /* HASH_SET */:
|
|
359
|
+
this.size = 0n;
|
|
360
|
+
this.index = 0n;
|
|
361
|
+
this.stack = await this.initStack(this.cursor, this.cursor.slotPtr.slot.value, INDEX_BLOCK_SIZE);
|
|
362
|
+
break;
|
|
363
|
+
case 12 /* COUNTED_HASH_MAP */:
|
|
364
|
+
case 13 /* COUNTED_HASH_SET */:
|
|
365
|
+
this.size = 0n;
|
|
366
|
+
this.index = 0n;
|
|
367
|
+
this.stack = await this.initStack(this.cursor, this.cursor.slotPtr.slot.value + 8n, INDEX_BLOCK_SIZE);
|
|
368
|
+
break;
|
|
369
|
+
default:
|
|
370
|
+
throw new UnexpectedTagException;
|
|
371
|
+
}
|
|
372
|
+
}
|
|
373
|
+
async initStack(cursor, position, blockSize) {
|
|
374
|
+
await cursor.db.core.seek(position);
|
|
375
|
+
const reader = cursor.db.core.reader();
|
|
376
|
+
const indexBlockBytes = new Uint8Array(blockSize);
|
|
377
|
+
await reader.readFully(indexBlockBytes);
|
|
378
|
+
const indexBlock = new Array(SLOT_COUNT);
|
|
379
|
+
const slotSize = blockSize / SLOT_COUNT;
|
|
380
|
+
for (let i = 0;i < SLOT_COUNT; i++) {
|
|
381
|
+
const slotBytes = indexBlockBytes.slice(i * slotSize, i * slotSize + Slot.LENGTH);
|
|
382
|
+
indexBlock[i] = Slot.fromBytes(slotBytes);
|
|
383
|
+
}
|
|
384
|
+
return [new IteratorLevel(position, indexBlock, 0)];
|
|
385
|
+
}
|
|
386
|
+
async hasNext() {
|
|
387
|
+
await this.init();
|
|
388
|
+
switch (this.cursor.slotPtr.slot.tag) {
|
|
389
|
+
case 0 /* NONE */:
|
|
390
|
+
return false;
|
|
391
|
+
case 2 /* ARRAY_LIST */:
|
|
392
|
+
return this.index < this.size;
|
|
393
|
+
case 3 /* LINKED_ARRAY_LIST */:
|
|
394
|
+
return this.index < this.size;
|
|
395
|
+
case 4 /* HASH_MAP */:
|
|
396
|
+
case 11 /* HASH_SET */:
|
|
397
|
+
case 12 /* COUNTED_HASH_MAP */:
|
|
398
|
+
case 13 /* COUNTED_HASH_SET */:
|
|
399
|
+
if (this.nextCursorMaybe === null) {
|
|
400
|
+
this.nextCursorMaybe = await this.nextInternal(INDEX_BLOCK_SIZE);
|
|
401
|
+
}
|
|
402
|
+
return this.nextCursorMaybe !== null;
|
|
403
|
+
default:
|
|
404
|
+
return false;
|
|
405
|
+
}
|
|
406
|
+
}
|
|
407
|
+
async next() {
|
|
408
|
+
await this.init();
|
|
409
|
+
switch (this.cursor.slotPtr.slot.tag) {
|
|
410
|
+
case 0 /* NONE */:
|
|
411
|
+
return null;
|
|
412
|
+
case 2 /* ARRAY_LIST */:
|
|
413
|
+
if (!await this.hasNext())
|
|
414
|
+
return null;
|
|
415
|
+
this.index += 1n;
|
|
416
|
+
return this.nextInternal(INDEX_BLOCK_SIZE);
|
|
417
|
+
case 3 /* LINKED_ARRAY_LIST */:
|
|
418
|
+
if (!await this.hasNext())
|
|
419
|
+
return null;
|
|
420
|
+
this.index += 1n;
|
|
421
|
+
return this.nextInternal(LINKED_ARRAY_LIST_INDEX_BLOCK_SIZE);
|
|
422
|
+
case 4 /* HASH_MAP */:
|
|
423
|
+
case 11 /* HASH_SET */:
|
|
424
|
+
case 12 /* COUNTED_HASH_MAP */:
|
|
425
|
+
case 13 /* COUNTED_HASH_SET */:
|
|
426
|
+
if (this.nextCursorMaybe !== null) {
|
|
427
|
+
const nextCursor = this.nextCursorMaybe;
|
|
428
|
+
this.nextCursorMaybe = null;
|
|
429
|
+
return nextCursor;
|
|
430
|
+
} else {
|
|
431
|
+
return this.nextInternal(INDEX_BLOCK_SIZE);
|
|
432
|
+
}
|
|
433
|
+
default:
|
|
434
|
+
throw new UnexpectedTagException;
|
|
435
|
+
}
|
|
436
|
+
}
|
|
437
|
+
async nextInternal(blockSize) {
|
|
438
|
+
while (this.stack.length > 0) {
|
|
439
|
+
const level = this.stack[this.stack.length - 1];
|
|
440
|
+
if (level.index === level.block.length) {
|
|
441
|
+
this.stack.pop();
|
|
442
|
+
if (this.stack.length > 0) {
|
|
443
|
+
this.stack[this.stack.length - 1].index += 1;
|
|
444
|
+
}
|
|
445
|
+
continue;
|
|
446
|
+
} else {
|
|
447
|
+
const nextSlot = level.block[level.index];
|
|
448
|
+
if (nextSlot.tag === 1 /* INDEX */) {
|
|
449
|
+
const nextPos = nextSlot.value;
|
|
450
|
+
await this.cursor.db.core.seek(nextPos);
|
|
451
|
+
const reader = this.cursor.db.core.reader();
|
|
452
|
+
const indexBlockBytes = new Uint8Array(blockSize);
|
|
453
|
+
await reader.readFully(indexBlockBytes);
|
|
454
|
+
const indexBlock = new Array(SLOT_COUNT);
|
|
455
|
+
const slotSize = blockSize / SLOT_COUNT;
|
|
456
|
+
for (let i = 0;i < SLOT_COUNT; i++) {
|
|
457
|
+
const slotBytes = indexBlockBytes.slice(i * slotSize, i * slotSize + Slot.LENGTH);
|
|
458
|
+
indexBlock[i] = Slot.fromBytes(slotBytes);
|
|
459
|
+
}
|
|
460
|
+
this.stack.push(new IteratorLevel(nextPos, indexBlock, 0));
|
|
461
|
+
continue;
|
|
462
|
+
} else {
|
|
463
|
+
this.stack[this.stack.length - 1].index += 1;
|
|
464
|
+
if (!nextSlot.empty()) {
|
|
465
|
+
const position = level.position + BigInt(level.index * Slot.LENGTH);
|
|
466
|
+
return new ReadCursor(new SlotPointer(position, nextSlot), this.cursor.db);
|
|
467
|
+
} else {
|
|
468
|
+
continue;
|
|
469
|
+
}
|
|
470
|
+
}
|
|
471
|
+
}
|
|
472
|
+
}
|
|
473
|
+
return null;
|
|
474
|
+
}
|
|
475
|
+
}
|
|
476
|
+
var ReadCursor;
|
|
477
|
+
var init_read_cursor = __esm(() => {
|
|
478
|
+
init_tag();
|
|
479
|
+
init_slot();
|
|
480
|
+
init_database();
|
|
481
|
+
init_exceptions();
|
|
482
|
+
init_writeable_data();
|
|
483
|
+
ReadCursor = class ReadCursor {
|
|
484
|
+
slotPtr;
|
|
485
|
+
db;
|
|
486
|
+
constructor(slotPtr, db) {
|
|
487
|
+
this.slotPtr = slotPtr;
|
|
488
|
+
this.db = db;
|
|
489
|
+
}
|
|
490
|
+
slot() {
|
|
491
|
+
return this.slotPtr.slot;
|
|
492
|
+
}
|
|
493
|
+
async readPath(path) {
|
|
494
|
+
try {
|
|
495
|
+
const slotPtr = await this.db.readSlotPointer(0 /* READ_ONLY */, path, 0, this.slotPtr);
|
|
496
|
+
return new ReadCursor(slotPtr, this.db);
|
|
497
|
+
} catch (e) {
|
|
498
|
+
if (e instanceof KeyNotFoundException) {
|
|
499
|
+
return null;
|
|
500
|
+
}
|
|
501
|
+
throw e;
|
|
502
|
+
}
|
|
503
|
+
}
|
|
504
|
+
async readPathSlot(path) {
|
|
505
|
+
try {
|
|
506
|
+
const slotPtr = await this.db.readSlotPointer(0 /* READ_ONLY */, path, 0, this.slotPtr);
|
|
507
|
+
if (!slotPtr.slot.empty()) {
|
|
508
|
+
return slotPtr.slot;
|
|
509
|
+
} else {
|
|
510
|
+
return null;
|
|
511
|
+
}
|
|
512
|
+
} catch (e) {
|
|
513
|
+
if (e instanceof KeyNotFoundException) {
|
|
514
|
+
return null;
|
|
515
|
+
}
|
|
516
|
+
throw e;
|
|
517
|
+
}
|
|
518
|
+
}
|
|
519
|
+
readUint() {
|
|
520
|
+
if (this.slotPtr.slot.tag !== 8 /* UINT */) {
|
|
521
|
+
throw new UnexpectedTagException;
|
|
522
|
+
}
|
|
523
|
+
if (this.slotPtr.slot.value < 0n)
|
|
524
|
+
throw new ExpectedUnsignedLongException;
|
|
525
|
+
return this.slotPtr.slot.value;
|
|
526
|
+
}
|
|
527
|
+
readInt() {
|
|
528
|
+
if (this.slotPtr.slot.tag !== 9 /* INT */) {
|
|
529
|
+
throw new UnexpectedTagException;
|
|
530
|
+
}
|
|
531
|
+
return this.slotPtr.slot.value;
|
|
532
|
+
}
|
|
533
|
+
readFloat() {
|
|
534
|
+
if (this.slotPtr.slot.tag !== 10 /* FLOAT */) {
|
|
535
|
+
throw new UnexpectedTagException;
|
|
536
|
+
}
|
|
537
|
+
const buffer = new ArrayBuffer(8);
|
|
538
|
+
const view = new DataView(buffer);
|
|
539
|
+
view.setBigInt64(0, this.slotPtr.slot.value, false);
|
|
540
|
+
return view.getFloat64(0, false);
|
|
541
|
+
}
|
|
542
|
+
async readBytes(maxSizeMaybe) {
|
|
543
|
+
const bytesObj = await this.readBytesObject(maxSizeMaybe);
|
|
544
|
+
return bytesObj.value;
|
|
545
|
+
}
|
|
546
|
+
async readBytesObject(maxSizeMaybe) {
|
|
547
|
+
const reader = this.db.core.reader();
|
|
548
|
+
switch (this.slotPtr.slot.tag) {
|
|
549
|
+
case 0 /* NONE */:
|
|
550
|
+
return new Bytes(new Uint8Array(0));
|
|
551
|
+
case 6 /* BYTES */: {
|
|
552
|
+
await this.db.core.seek(this.slotPtr.slot.value);
|
|
553
|
+
const valueSize = await reader.readLong();
|
|
554
|
+
if (maxSizeMaybe !== undefined && valueSize > maxSizeMaybe) {
|
|
555
|
+
throw new StreamTooLongException;
|
|
556
|
+
}
|
|
557
|
+
const startPosition = await this.db.core.position();
|
|
558
|
+
const value = new Uint8Array(Number(valueSize));
|
|
559
|
+
await reader.readFully(value);
|
|
560
|
+
let formatTag = null;
|
|
561
|
+
if (this.slotPtr.slot.full) {
|
|
562
|
+
await this.db.core.seek(startPosition + valueSize);
|
|
563
|
+
formatTag = new Uint8Array(2);
|
|
564
|
+
await reader.readFully(formatTag);
|
|
565
|
+
}
|
|
566
|
+
return new Bytes(value, formatTag);
|
|
567
|
+
}
|
|
568
|
+
case 7 /* SHORT_BYTES */: {
|
|
569
|
+
const buffer = new ArrayBuffer(8);
|
|
570
|
+
const view = new DataView(buffer);
|
|
571
|
+
view.setBigInt64(0, this.slotPtr.slot.value, false);
|
|
572
|
+
const bytes = new Uint8Array(buffer);
|
|
573
|
+
const totalSize = this.slotPtr.slot.full ? bytes.length - 2 : bytes.length;
|
|
574
|
+
let valueSize = 0;
|
|
575
|
+
for (const b of bytes) {
|
|
576
|
+
if (b === 0 || valueSize === totalSize)
|
|
577
|
+
break;
|
|
578
|
+
valueSize += 1;
|
|
579
|
+
}
|
|
580
|
+
if (maxSizeMaybe !== undefined && BigInt(valueSize) > maxSizeMaybe) {
|
|
581
|
+
throw new StreamTooLongException;
|
|
582
|
+
}
|
|
583
|
+
let formatTag = null;
|
|
584
|
+
if (this.slotPtr.slot.full) {
|
|
585
|
+
formatTag = bytes.slice(totalSize, bytes.length);
|
|
586
|
+
}
|
|
587
|
+
return new Bytes(bytes.slice(0, valueSize), formatTag);
|
|
588
|
+
}
|
|
589
|
+
default:
|
|
590
|
+
throw new UnexpectedTagException;
|
|
591
|
+
}
|
|
592
|
+
}
|
|
593
|
+
async readKeyValuePair() {
|
|
594
|
+
const reader = this.db.core.reader();
|
|
595
|
+
if (this.slotPtr.slot.tag !== 5 /* KV_PAIR */) {
|
|
596
|
+
throw new UnexpectedTagException;
|
|
597
|
+
}
|
|
598
|
+
await this.db.core.seek(this.slotPtr.slot.value);
|
|
599
|
+
const kvPairBytes = new Uint8Array(KeyValuePair.length(this.db.header.hashSize));
|
|
600
|
+
await reader.readFully(kvPairBytes);
|
|
601
|
+
const kvPair = KeyValuePair.fromBytes(kvPairBytes, this.db.header.hashSize);
|
|
602
|
+
const hashPos = this.slotPtr.slot.value;
|
|
603
|
+
const keySlotPos = hashPos + BigInt(this.db.header.hashSize);
|
|
604
|
+
const valueSlotPos = keySlotPos + BigInt(Slot.LENGTH);
|
|
605
|
+
return new KeyValuePairCursor(new ReadCursor(new SlotPointer(valueSlotPos, kvPair.valueSlot), this.db), new ReadCursor(new SlotPointer(keySlotPos, kvPair.keySlot), this.db), kvPair.hash);
|
|
606
|
+
}
|
|
607
|
+
async reader() {
|
|
608
|
+
const reader = this.db.core.reader();
|
|
609
|
+
switch (this.slotPtr.slot.tag) {
|
|
610
|
+
case 6 /* BYTES */: {
|
|
611
|
+
await this.db.core.seek(this.slotPtr.slot.value);
|
|
612
|
+
const size = await reader.readLong();
|
|
613
|
+
const startPosition = await this.db.core.position();
|
|
614
|
+
return new Reader(this, size, startPosition, 0n);
|
|
615
|
+
}
|
|
616
|
+
case 7 /* SHORT_BYTES */: {
|
|
617
|
+
const buffer = new ArrayBuffer(8);
|
|
618
|
+
const view = new DataView(buffer);
|
|
619
|
+
view.setBigInt64(0, this.slotPtr.slot.value, false);
|
|
620
|
+
const bytes = new Uint8Array(buffer);
|
|
621
|
+
const totalSize = this.slotPtr.slot.full ? bytes.length - 2 : bytes.length;
|
|
622
|
+
let valueSize = 0;
|
|
623
|
+
for (const b of bytes) {
|
|
624
|
+
if (b === 0 || valueSize === totalSize)
|
|
625
|
+
break;
|
|
626
|
+
valueSize += 1;
|
|
627
|
+
}
|
|
628
|
+
const startPosition = this.slotPtr.position + 1n;
|
|
629
|
+
return new Reader(this, BigInt(valueSize), startPosition, 0n);
|
|
630
|
+
}
|
|
631
|
+
default:
|
|
632
|
+
throw new UnexpectedTagException;
|
|
633
|
+
}
|
|
634
|
+
}
|
|
635
|
+
async count() {
|
|
636
|
+
const reader = this.db.core.reader();
|
|
637
|
+
switch (this.slotPtr.slot.tag) {
|
|
638
|
+
case 0 /* NONE */:
|
|
639
|
+
return 0n;
|
|
640
|
+
case 2 /* ARRAY_LIST */: {
|
|
641
|
+
await this.db.core.seek(this.slotPtr.slot.value);
|
|
642
|
+
const headerBytes = new Uint8Array(ArrayListHeader.LENGTH);
|
|
643
|
+
await reader.readFully(headerBytes);
|
|
644
|
+
const header = ArrayListHeader.fromBytes(headerBytes);
|
|
645
|
+
return header.size;
|
|
646
|
+
}
|
|
647
|
+
case 3 /* LINKED_ARRAY_LIST */: {
|
|
648
|
+
await this.db.core.seek(this.slotPtr.slot.value);
|
|
649
|
+
const headerBytes = new Uint8Array(LinkedArrayListHeader.LENGTH);
|
|
650
|
+
await reader.readFully(headerBytes);
|
|
651
|
+
const header = LinkedArrayListHeader.fromBytes(headerBytes);
|
|
652
|
+
return header.size;
|
|
653
|
+
}
|
|
654
|
+
case 6 /* BYTES */: {
|
|
655
|
+
await this.db.core.seek(this.slotPtr.slot.value);
|
|
656
|
+
return reader.readLong();
|
|
657
|
+
}
|
|
658
|
+
case 7 /* SHORT_BYTES */: {
|
|
659
|
+
const buffer = new ArrayBuffer(8);
|
|
660
|
+
const view = new DataView(buffer);
|
|
661
|
+
view.setBigInt64(0, this.slotPtr.slot.value, false);
|
|
662
|
+
const bytes = new Uint8Array(buffer);
|
|
663
|
+
const totalSize = this.slotPtr.slot.full ? bytes.length - 2 : bytes.length;
|
|
664
|
+
let size = 0;
|
|
665
|
+
for (const b of bytes) {
|
|
666
|
+
if (b === 0 || size === totalSize)
|
|
667
|
+
break;
|
|
668
|
+
size += 1;
|
|
669
|
+
}
|
|
670
|
+
return BigInt(size);
|
|
671
|
+
}
|
|
672
|
+
case 12 /* COUNTED_HASH_MAP */:
|
|
673
|
+
case 13 /* COUNTED_HASH_SET */: {
|
|
674
|
+
await this.db.core.seek(this.slotPtr.slot.value);
|
|
675
|
+
return reader.readLong();
|
|
676
|
+
}
|
|
677
|
+
default:
|
|
678
|
+
throw new UnexpectedTagException;
|
|
679
|
+
}
|
|
680
|
+
}
|
|
681
|
+
async* [Symbol.asyncIterator]() {
|
|
682
|
+
const iterator = new CursorIterator(this);
|
|
683
|
+
await iterator.init();
|
|
684
|
+
while (await iterator.hasNext()) {
|
|
685
|
+
const next = await iterator.next();
|
|
686
|
+
if (next !== null) {
|
|
687
|
+
yield next;
|
|
688
|
+
}
|
|
689
|
+
}
|
|
690
|
+
}
|
|
691
|
+
iterator() {
|
|
692
|
+
return new CursorIterator(this);
|
|
693
|
+
}
|
|
694
|
+
};
|
|
695
|
+
});
|
|
696
|
+
|
|
697
|
+
// src/write-cursor.ts
|
|
698
|
+
var exports_write_cursor = {};
|
|
699
|
+
__export(exports_write_cursor, {
|
|
700
|
+
Writer: () => Writer,
|
|
701
|
+
WriteKeyValuePairCursor: () => WriteKeyValuePairCursor,
|
|
702
|
+
WriteCursorIterator: () => WriteCursorIterator,
|
|
703
|
+
WriteCursor: () => WriteCursor
|
|
704
|
+
});
|
|
705
|
+
|
|
706
|
+
class Writer {
|
|
707
|
+
parent;
|
|
708
|
+
size;
|
|
709
|
+
slot;
|
|
710
|
+
startPosition;
|
|
711
|
+
relativePosition;
|
|
712
|
+
formatTag = null;
|
|
713
|
+
constructor(parent, size, slot, startPosition, relativePosition) {
|
|
714
|
+
this.parent = parent;
|
|
715
|
+
this.size = size;
|
|
716
|
+
this.slot = slot;
|
|
717
|
+
this.startPosition = startPosition;
|
|
718
|
+
this.relativePosition = relativePosition;
|
|
719
|
+
}
|
|
720
|
+
async write(buffer) {
|
|
721
|
+
if (this.size < this.relativePosition)
|
|
722
|
+
throw new EndOfStreamException;
|
|
723
|
+
await this.parent.db.core.seek(this.startPosition + this.relativePosition);
|
|
724
|
+
const writer = this.parent.db.core.writer();
|
|
725
|
+
await writer.write(buffer);
|
|
726
|
+
this.relativePosition += BigInt(buffer.length);
|
|
727
|
+
if (this.relativePosition > this.size) {
|
|
728
|
+
this.size = this.relativePosition;
|
|
729
|
+
}
|
|
730
|
+
}
|
|
731
|
+
async finish() {
|
|
732
|
+
const writer = this.parent.db.core.writer();
|
|
733
|
+
if (this.formatTag !== null) {
|
|
734
|
+
this.slot = this.slot.withFull(true);
|
|
735
|
+
const formatTagPos = await this.parent.db.core.length();
|
|
736
|
+
await this.parent.db.core.seek(formatTagPos);
|
|
737
|
+
if (this.startPosition + this.size !== formatTagPos)
|
|
738
|
+
throw new UnexpectedWriterPositionException;
|
|
739
|
+
await writer.write(this.formatTag);
|
|
740
|
+
}
|
|
741
|
+
await this.parent.db.core.seek(this.slot.value);
|
|
742
|
+
await writer.writeLong(this.size);
|
|
743
|
+
if (this.parent.slotPtr.position === null)
|
|
744
|
+
throw new CursorNotWriteableException;
|
|
745
|
+
const position = this.parent.slotPtr.position;
|
|
746
|
+
await this.parent.db.core.seek(position);
|
|
747
|
+
await writer.write(this.slot.toBytes());
|
|
748
|
+
this.parent.slotPtr = this.parent.slotPtr.withSlot(this.slot);
|
|
749
|
+
}
|
|
750
|
+
seek(position) {
|
|
751
|
+
if (position <= this.size) {
|
|
752
|
+
this.relativePosition = position;
|
|
753
|
+
}
|
|
754
|
+
}
|
|
755
|
+
}
|
|
756
|
+
var WriteKeyValuePairCursor, WriteCursor, WriteCursorIterator;
|
|
757
|
+
var init_write_cursor = __esm(() => {
|
|
758
|
+
init_tag();
|
|
759
|
+
init_slot();
|
|
760
|
+
init_database();
|
|
761
|
+
init_read_cursor();
|
|
762
|
+
init_exceptions();
|
|
763
|
+
WriteKeyValuePairCursor = class WriteKeyValuePairCursor extends KeyValuePairCursor {
|
|
764
|
+
valueCursor;
|
|
765
|
+
keyCursor;
|
|
766
|
+
constructor(valueCursor, keyCursor, hash) {
|
|
767
|
+
super(valueCursor, keyCursor, hash);
|
|
768
|
+
this.valueCursor = valueCursor;
|
|
769
|
+
this.keyCursor = keyCursor;
|
|
770
|
+
}
|
|
771
|
+
};
|
|
772
|
+
WriteCursor = class WriteCursor extends ReadCursor {
|
|
773
|
+
constructor(slotPtr, db) {
|
|
774
|
+
super(slotPtr, db);
|
|
775
|
+
}
|
|
776
|
+
async writePath(path) {
|
|
777
|
+
const slotPtr = await this.db.readSlotPointer(1 /* READ_WRITE */, path, 0, this.slotPtr);
|
|
778
|
+
if (this.db.txStart === null) {
|
|
779
|
+
await this.db.core.sync();
|
|
780
|
+
}
|
|
781
|
+
return new WriteCursor(slotPtr, this.db);
|
|
782
|
+
}
|
|
783
|
+
async write(data) {
|
|
784
|
+
const cursor = await this.writePath([new WriteData(data)]);
|
|
785
|
+
this.slotPtr = cursor.slotPtr;
|
|
786
|
+
}
|
|
787
|
+
async writeIfEmpty(data) {
|
|
788
|
+
if (this.slotPtr.slot.empty()) {
|
|
789
|
+
await this.write(data);
|
|
790
|
+
}
|
|
791
|
+
}
|
|
792
|
+
async readKeyValuePair() {
|
|
793
|
+
const kvPairCursor = await super.readKeyValuePair();
|
|
794
|
+
return new WriteKeyValuePairCursor(new WriteCursor(kvPairCursor.valueCursor.slotPtr, this.db), new WriteCursor(kvPairCursor.keyCursor.slotPtr, this.db), kvPairCursor.hash);
|
|
795
|
+
}
|
|
796
|
+
async writer() {
|
|
797
|
+
const writer = this.db.core.writer();
|
|
798
|
+
const ptrPos = await this.db.core.length();
|
|
799
|
+
await this.db.core.seek(ptrPos);
|
|
800
|
+
await writer.writeLong(0n);
|
|
801
|
+
const startPosition = await this.db.core.length();
|
|
802
|
+
return new Writer(this, 0n, new Slot(ptrPos, 6 /* BYTES */), startPosition, 0n);
|
|
803
|
+
}
|
|
804
|
+
async* [Symbol.asyncIterator]() {
|
|
805
|
+
const iterator = new WriteCursorIterator(this);
|
|
806
|
+
await iterator.init();
|
|
807
|
+
while (await iterator.hasNext()) {
|
|
808
|
+
const next = await iterator.next();
|
|
809
|
+
if (next !== null) {
|
|
810
|
+
yield next;
|
|
811
|
+
}
|
|
812
|
+
}
|
|
813
|
+
}
|
|
814
|
+
iterator() {
|
|
815
|
+
return new WriteCursorIterator(this);
|
|
816
|
+
}
|
|
817
|
+
};
|
|
818
|
+
WriteCursorIterator = class WriteCursorIterator extends CursorIterator {
|
|
819
|
+
constructor(cursor) {
|
|
820
|
+
super(cursor);
|
|
821
|
+
}
|
|
822
|
+
async next() {
|
|
823
|
+
const readCursor = await super.next();
|
|
824
|
+
if (readCursor !== null) {
|
|
825
|
+
return new WriteCursor(readCursor.slotPtr, readCursor.db);
|
|
826
|
+
} else {
|
|
827
|
+
return null;
|
|
828
|
+
}
|
|
829
|
+
}
|
|
830
|
+
};
|
|
831
|
+
});
|
|
832
|
+
|
|
833
|
+
// src/database.ts
|
|
834
|
+
class Header {
|
|
835
|
+
hashId;
|
|
836
|
+
hashSize;
|
|
837
|
+
version;
|
|
838
|
+
tag;
|
|
839
|
+
magicNumber;
|
|
840
|
+
static LENGTH = 12;
|
|
841
|
+
constructor(hashId, hashSize, version, tag, magicNumber) {
|
|
842
|
+
this.hashId = hashId;
|
|
843
|
+
this.hashSize = hashSize;
|
|
844
|
+
this.version = version;
|
|
845
|
+
this.tag = tag;
|
|
846
|
+
this.magicNumber = magicNumber;
|
|
847
|
+
}
|
|
848
|
+
toBytes() {
|
|
849
|
+
const buffer = new ArrayBuffer(Header.LENGTH);
|
|
850
|
+
const view = new DataView(buffer);
|
|
851
|
+
const arr = new Uint8Array(buffer);
|
|
852
|
+
arr.set(this.magicNumber, 0);
|
|
853
|
+
view.setUint8(3, this.tag);
|
|
854
|
+
view.setInt16(4, this.version, false);
|
|
855
|
+
view.setInt16(6, this.hashSize, false);
|
|
856
|
+
view.setInt32(8, this.hashId, false);
|
|
857
|
+
return arr;
|
|
858
|
+
}
|
|
859
|
+
static async read(core) {
|
|
860
|
+
const reader = core.reader();
|
|
861
|
+
const magicNumber = new Uint8Array(3);
|
|
862
|
+
await reader.readFully(magicNumber);
|
|
863
|
+
const tagByte = await reader.readByte();
|
|
864
|
+
const tag = tagValueOf(tagByte & 127);
|
|
865
|
+
const version = await reader.readShort();
|
|
866
|
+
const hashSize = await reader.readShort();
|
|
867
|
+
const hashId = await reader.readInt();
|
|
868
|
+
return new Header(hashId, hashSize, version, tag, magicNumber);
|
|
869
|
+
}
|
|
870
|
+
async write(core) {
|
|
871
|
+
const writer = core.writer();
|
|
872
|
+
await writer.write(this.toBytes());
|
|
873
|
+
}
|
|
874
|
+
validate() {
|
|
875
|
+
if (!arraysEqual(this.magicNumber, MAGIC_NUMBER)) {
|
|
876
|
+
throw new InvalidDatabaseException;
|
|
877
|
+
}
|
|
878
|
+
if (this.version > VERSION) {
|
|
879
|
+
throw new InvalidVersionException;
|
|
880
|
+
}
|
|
881
|
+
}
|
|
882
|
+
withTag(tag) {
|
|
883
|
+
return new Header(this.hashId, this.hashSize, this.version, tag, this.magicNumber);
|
|
884
|
+
}
|
|
885
|
+
}
|
|
886
|
+
|
|
887
|
+
class ArrayListHeader {
|
|
888
|
+
ptr;
|
|
889
|
+
size;
|
|
890
|
+
static LENGTH = 16;
|
|
891
|
+
constructor(ptr, size) {
|
|
892
|
+
this.ptr = ptr;
|
|
893
|
+
this.size = size;
|
|
894
|
+
}
|
|
895
|
+
toBytes() {
|
|
896
|
+
const buffer = new ArrayBuffer(ArrayListHeader.LENGTH);
|
|
897
|
+
const view = new DataView(buffer);
|
|
898
|
+
view.setBigInt64(0, this.size, false);
|
|
899
|
+
view.setBigInt64(8, this.ptr, false);
|
|
900
|
+
return new Uint8Array(buffer);
|
|
901
|
+
}
|
|
902
|
+
static fromBytes(bytes) {
|
|
903
|
+
const view = new DataView(bytes.buffer, bytes.byteOffset, bytes.byteLength);
|
|
904
|
+
const size = checkLong(view.getBigInt64(0, false));
|
|
905
|
+
const ptr = checkLong(view.getBigInt64(8, false));
|
|
906
|
+
return new ArrayListHeader(ptr, size);
|
|
907
|
+
}
|
|
908
|
+
withPtr(ptr) {
|
|
909
|
+
return new ArrayListHeader(ptr, this.size);
|
|
910
|
+
}
|
|
911
|
+
}
|
|
912
|
+
|
|
913
|
+
class LinkedArrayListHeader {
|
|
914
|
+
shift;
|
|
915
|
+
ptr;
|
|
916
|
+
size;
|
|
917
|
+
static LENGTH = 17;
|
|
918
|
+
constructor(shift, ptr, size) {
|
|
919
|
+
this.shift = shift;
|
|
920
|
+
this.ptr = ptr;
|
|
921
|
+
this.size = size;
|
|
922
|
+
}
|
|
923
|
+
toBytes() {
|
|
924
|
+
const buffer = new ArrayBuffer(LinkedArrayListHeader.LENGTH);
|
|
925
|
+
const view = new DataView(buffer);
|
|
926
|
+
view.setBigInt64(0, this.size, false);
|
|
927
|
+
view.setBigInt64(8, this.ptr, false);
|
|
928
|
+
view.setUint8(16, this.shift & 63);
|
|
929
|
+
return new Uint8Array(buffer);
|
|
930
|
+
}
|
|
931
|
+
static fromBytes(bytes) {
|
|
932
|
+
const view = new DataView(bytes.buffer, bytes.byteOffset, bytes.byteLength);
|
|
933
|
+
const size = checkLong(view.getBigInt64(0, false));
|
|
934
|
+
const ptr = checkLong(view.getBigInt64(8, false));
|
|
935
|
+
const shift = view.getUint8(16) & 63;
|
|
936
|
+
return new LinkedArrayListHeader(shift, ptr, size);
|
|
937
|
+
}
|
|
938
|
+
withPtr(ptr) {
|
|
939
|
+
return new LinkedArrayListHeader(this.shift, ptr, this.size);
|
|
940
|
+
}
|
|
941
|
+
}
|
|
942
|
+
|
|
943
|
+
class KeyValuePair {
|
|
944
|
+
valueSlot;
|
|
945
|
+
keySlot;
|
|
946
|
+
hash;
|
|
947
|
+
constructor(valueSlot, keySlot, hash) {
|
|
948
|
+
this.valueSlot = valueSlot;
|
|
949
|
+
this.keySlot = keySlot;
|
|
950
|
+
this.hash = hash;
|
|
951
|
+
}
|
|
952
|
+
static length(hashSize) {
|
|
953
|
+
return hashSize + Slot.LENGTH * 2;
|
|
954
|
+
}
|
|
955
|
+
toBytes() {
|
|
956
|
+
const buffer = new Uint8Array(KeyValuePair.length(this.hash.length));
|
|
957
|
+
buffer.set(this.hash, 0);
|
|
958
|
+
buffer.set(this.keySlot.toBytes(), this.hash.length);
|
|
959
|
+
buffer.set(this.valueSlot.toBytes(), this.hash.length + Slot.LENGTH);
|
|
960
|
+
return buffer;
|
|
961
|
+
}
|
|
962
|
+
static fromBytes(bytes, hashSize) {
|
|
963
|
+
const hash = bytes.slice(0, hashSize);
|
|
964
|
+
const keySlotBytes = bytes.slice(hashSize, hashSize + Slot.LENGTH);
|
|
965
|
+
const keySlot = Slot.fromBytes(keySlotBytes);
|
|
966
|
+
const valueSlotBytes = bytes.slice(hashSize + Slot.LENGTH, hashSize + Slot.LENGTH * 2);
|
|
967
|
+
const valueSlot = Slot.fromBytes(valueSlotBytes);
|
|
968
|
+
return new KeyValuePair(valueSlot, keySlot, hash);
|
|
969
|
+
}
|
|
970
|
+
}
|
|
971
|
+
|
|
972
|
+
class LinkedArrayListSlotPointer {
|
|
973
|
+
slotPtr;
|
|
974
|
+
leafCount;
|
|
975
|
+
constructor(slotPtr, leafCount) {
|
|
976
|
+
this.slotPtr = slotPtr;
|
|
977
|
+
this.leafCount = leafCount;
|
|
978
|
+
}
|
|
979
|
+
withSlotPointer(slotPtr) {
|
|
980
|
+
return new LinkedArrayListSlotPointer(slotPtr, this.leafCount);
|
|
981
|
+
}
|
|
982
|
+
}
|
|
983
|
+
|
|
984
|
+
class LinkedArrayListBlockInfo {
|
|
985
|
+
block;
|
|
986
|
+
i;
|
|
987
|
+
parentSlot;
|
|
988
|
+
constructor(block, i, parentSlot) {
|
|
989
|
+
this.block = block;
|
|
990
|
+
this.i = i;
|
|
991
|
+
this.parentSlot = parentSlot;
|
|
992
|
+
}
|
|
993
|
+
}
|
|
994
|
+
|
|
995
|
+
class HashMapGetKVPair {
|
|
996
|
+
hash;
|
|
997
|
+
kind = "kv_pair";
|
|
998
|
+
constructor(hash) {
|
|
999
|
+
this.hash = hash;
|
|
1000
|
+
}
|
|
1001
|
+
}
|
|
1002
|
+
|
|
1003
|
+
class HashMapGetKey {
|
|
1004
|
+
hash;
|
|
1005
|
+
kind = "key";
|
|
1006
|
+
constructor(hash) {
|
|
1007
|
+
this.hash = hash;
|
|
1008
|
+
}
|
|
1009
|
+
}
|
|
1010
|
+
|
|
1011
|
+
class HashMapGetValue {
|
|
1012
|
+
hash;
|
|
1013
|
+
kind = "value";
|
|
1014
|
+
constructor(hash) {
|
|
1015
|
+
this.hash = hash;
|
|
1016
|
+
}
|
|
1017
|
+
}
|
|
1018
|
+
|
|
1019
|
+
class ArrayListInit {
|
|
1020
|
+
kind = "ArrayListInit";
|
|
1021
|
+
async readSlotPointer(db, isTopLevel, writeMode, path, pathI, slotPtr) {
|
|
1022
|
+
if (writeMode === 0 /* READ_ONLY */)
|
|
1023
|
+
throw new WriteNotAllowedException;
|
|
1024
|
+
if (isTopLevel) {
|
|
1025
|
+
const writer = db.core.writer();
|
|
1026
|
+
if (db.header.tag === 0 /* NONE */) {
|
|
1027
|
+
await db.core.seek(BigInt(Header.LENGTH));
|
|
1028
|
+
const arrayListPtr = BigInt(Header.LENGTH + TopLevelArrayListHeader.LENGTH);
|
|
1029
|
+
await writer.write(new TopLevelArrayListHeader(0n, new ArrayListHeader(arrayListPtr, 0n)).toBytes());
|
|
1030
|
+
await writer.write(new Uint8Array(INDEX_BLOCK_SIZE));
|
|
1031
|
+
await db.core.seek(0n);
|
|
1032
|
+
db.header = db.header.withTag(2 /* ARRAY_LIST */);
|
|
1033
|
+
await writer.write(db.header.toBytes());
|
|
1034
|
+
}
|
|
1035
|
+
const nextSlotPtr = slotPtr.withSlot(slotPtr.slot.withTag(2 /* ARRAY_LIST */));
|
|
1036
|
+
return db.readSlotPointer(writeMode, path, pathI + 1, nextSlotPtr);
|
|
1037
|
+
}
|
|
1038
|
+
if (slotPtr.position === null)
|
|
1039
|
+
throw new CursorNotWriteableException;
|
|
1040
|
+
const position = slotPtr.position;
|
|
1041
|
+
switch (slotPtr.slot.tag) {
|
|
1042
|
+
case 0 /* NONE */: {
|
|
1043
|
+
const writer = db.core.writer();
|
|
1044
|
+
let arrayListStart = await db.core.length();
|
|
1045
|
+
await db.core.seek(arrayListStart);
|
|
1046
|
+
const arrayListPtr = arrayListStart + BigInt(ArrayListHeader.LENGTH);
|
|
1047
|
+
await writer.write(new ArrayListHeader(arrayListPtr, 0n).toBytes());
|
|
1048
|
+
await writer.write(new Uint8Array(INDEX_BLOCK_SIZE));
|
|
1049
|
+
const nextSlotPtr = new SlotPointer(position, new Slot(arrayListStart, 2 /* ARRAY_LIST */));
|
|
1050
|
+
await db.core.seek(position);
|
|
1051
|
+
await writer.write(nextSlotPtr.slot.toBytes());
|
|
1052
|
+
return db.readSlotPointer(writeMode, path, pathI + 1, nextSlotPtr);
|
|
1053
|
+
}
|
|
1054
|
+
case 2 /* ARRAY_LIST */: {
|
|
1055
|
+
const reader = db.core.reader();
|
|
1056
|
+
const writer = db.core.writer();
|
|
1057
|
+
let arrayListStart = slotPtr.slot.value;
|
|
1058
|
+
if (db.txStart !== null) {
|
|
1059
|
+
if (arrayListStart < db.txStart) {
|
|
1060
|
+
await db.core.seek(arrayListStart);
|
|
1061
|
+
const headerBytes = new Uint8Array(ArrayListHeader.LENGTH);
|
|
1062
|
+
await reader.readFully(headerBytes);
|
|
1063
|
+
const header = ArrayListHeader.fromBytes(headerBytes);
|
|
1064
|
+
await db.core.seek(header.ptr);
|
|
1065
|
+
const arrayListIndexBlock = new Uint8Array(INDEX_BLOCK_SIZE);
|
|
1066
|
+
await reader.readFully(arrayListIndexBlock);
|
|
1067
|
+
arrayListStart = await db.core.length();
|
|
1068
|
+
await db.core.seek(arrayListStart);
|
|
1069
|
+
const nextArrayListPtr = arrayListStart + BigInt(ArrayListHeader.LENGTH);
|
|
1070
|
+
const newHeader = header.withPtr(nextArrayListPtr);
|
|
1071
|
+
await writer.write(newHeader.toBytes());
|
|
1072
|
+
await writer.write(arrayListIndexBlock);
|
|
1073
|
+
}
|
|
1074
|
+
} else if (db.header.tag === 2 /* ARRAY_LIST */) {
|
|
1075
|
+
throw new ExpectedTxStartException;
|
|
1076
|
+
}
|
|
1077
|
+
const nextSlotPtr = new SlotPointer(position, new Slot(arrayListStart, 2 /* ARRAY_LIST */));
|
|
1078
|
+
await db.core.seek(position);
|
|
1079
|
+
await writer.write(nextSlotPtr.slot.toBytes());
|
|
1080
|
+
return db.readSlotPointer(writeMode, path, pathI + 1, nextSlotPtr);
|
|
1081
|
+
}
|
|
1082
|
+
default:
|
|
1083
|
+
throw new UnexpectedTagException;
|
|
1084
|
+
}
|
|
1085
|
+
}
|
|
1086
|
+
}
|
|
1087
|
+
|
|
1088
|
+
class ArrayListGet2 {
|
|
1089
|
+
index;
|
|
1090
|
+
kind = "ArrayListGet";
|
|
1091
|
+
constructor(index) {
|
|
1092
|
+
this.index = index;
|
|
1093
|
+
}
|
|
1094
|
+
async readSlotPointer(db, isTopLevel, writeMode, path, pathI, slotPtr) {
|
|
1095
|
+
const tag = isTopLevel ? db.header.tag : slotPtr.slot.tag;
|
|
1096
|
+
switch (tag) {
|
|
1097
|
+
case 0 /* NONE */:
|
|
1098
|
+
throw new KeyNotFoundException;
|
|
1099
|
+
case 2 /* ARRAY_LIST */:
|
|
1100
|
+
break;
|
|
1101
|
+
default:
|
|
1102
|
+
throw new UnexpectedTagException;
|
|
1103
|
+
}
|
|
1104
|
+
const nextArrayListStart = slotPtr.slot.value;
|
|
1105
|
+
let index = this.index;
|
|
1106
|
+
await db.core.seek(nextArrayListStart);
|
|
1107
|
+
const reader = db.core.reader();
|
|
1108
|
+
const headerBytes = new Uint8Array(ArrayListHeader.LENGTH);
|
|
1109
|
+
await reader.readFully(headerBytes);
|
|
1110
|
+
const header = ArrayListHeader.fromBytes(headerBytes);
|
|
1111
|
+
if (index >= header.size || index < -header.size) {
|
|
1112
|
+
throw new KeyNotFoundException;
|
|
1113
|
+
}
|
|
1114
|
+
const key = index < 0n ? header.size - bigAbs(index) : index;
|
|
1115
|
+
const lastKey = header.size - 1n;
|
|
1116
|
+
const shift = lastKey < BigInt(SLOT_COUNT) ? 0 : Math.floor(Math.log(Number(lastKey)) / Math.log(SLOT_COUNT));
|
|
1117
|
+
const finalSlotPtr = await db.readArrayListSlot(header.ptr, key, shift, writeMode, isTopLevel);
|
|
1118
|
+
return db.readSlotPointer(writeMode, path, pathI + 1, finalSlotPtr);
|
|
1119
|
+
}
|
|
1120
|
+
}
|
|
1121
|
+
|
|
1122
|
+
class ArrayListAppend {
|
|
1123
|
+
kind = "ArrayListAppend";
|
|
1124
|
+
async readSlotPointer(db, isTopLevel, writeMode, path, pathI, slotPtr) {
|
|
1125
|
+
if (writeMode === 0 /* READ_ONLY */)
|
|
1126
|
+
throw new WriteNotAllowedException;
|
|
1127
|
+
const tag = isTopLevel ? db.header.tag : slotPtr.slot.tag;
|
|
1128
|
+
if (tag !== 2 /* ARRAY_LIST */)
|
|
1129
|
+
throw new UnexpectedTagException;
|
|
1130
|
+
const reader = db.core.reader();
|
|
1131
|
+
const nextArrayListStart = slotPtr.slot.value;
|
|
1132
|
+
await db.core.seek(nextArrayListStart);
|
|
1133
|
+
const headerBytes = new Uint8Array(ArrayListHeader.LENGTH);
|
|
1134
|
+
await reader.readFully(headerBytes);
|
|
1135
|
+
const origHeader = ArrayListHeader.fromBytes(headerBytes);
|
|
1136
|
+
const appendResult = await db.readArrayListSlotAppend(origHeader, writeMode, isTopLevel);
|
|
1137
|
+
const finalSlotPtr = await db.readSlotPointer(writeMode, path, pathI + 1, appendResult.slotPtr);
|
|
1138
|
+
const writer = db.core.writer();
|
|
1139
|
+
if (isTopLevel) {
|
|
1140
|
+
await db.core.flush();
|
|
1141
|
+
const fileSize = await db.core.length();
|
|
1142
|
+
const header = new TopLevelArrayListHeader(fileSize, appendResult.header);
|
|
1143
|
+
await db.core.seek(nextArrayListStart);
|
|
1144
|
+
await writer.write(header.toBytes());
|
|
1145
|
+
} else {
|
|
1146
|
+
await db.core.seek(nextArrayListStart);
|
|
1147
|
+
await writer.write(appendResult.header.toBytes());
|
|
1148
|
+
}
|
|
1149
|
+
return finalSlotPtr;
|
|
1150
|
+
}
|
|
1151
|
+
}
|
|
1152
|
+
|
|
1153
|
+
class ArrayListSlice {
|
|
1154
|
+
size;
|
|
1155
|
+
kind = "ArrayListSlice";
|
|
1156
|
+
constructor(size) {
|
|
1157
|
+
this.size = size;
|
|
1158
|
+
}
|
|
1159
|
+
async readSlotPointer(db, isTopLevel, writeMode, path, pathI, slotPtr) {
|
|
1160
|
+
if (writeMode === 0 /* READ_ONLY */)
|
|
1161
|
+
throw new WriteNotAllowedException;
|
|
1162
|
+
if (slotPtr.slot.tag !== 2 /* ARRAY_LIST */)
|
|
1163
|
+
throw new UnexpectedTagException;
|
|
1164
|
+
const reader = db.core.reader();
|
|
1165
|
+
const nextArrayListStart = slotPtr.slot.value;
|
|
1166
|
+
await db.core.seek(nextArrayListStart);
|
|
1167
|
+
const headerBytes = new Uint8Array(ArrayListHeader.LENGTH);
|
|
1168
|
+
await reader.readFully(headerBytes);
|
|
1169
|
+
const origHeader = ArrayListHeader.fromBytes(headerBytes);
|
|
1170
|
+
const sliceHeader = await db.readArrayListSlice(origHeader, this.size);
|
|
1171
|
+
const finalSlotPtr = await db.readSlotPointer(writeMode, path, pathI + 1, slotPtr);
|
|
1172
|
+
const writer = db.core.writer();
|
|
1173
|
+
await db.core.seek(nextArrayListStart);
|
|
1174
|
+
await writer.write(sliceHeader.toBytes());
|
|
1175
|
+
return finalSlotPtr;
|
|
1176
|
+
}
|
|
1177
|
+
}
|
|
1178
|
+
|
|
1179
|
+
class LinkedArrayListInit {
|
|
1180
|
+
kind = "LinkedArrayListInit";
|
|
1181
|
+
async readSlotPointer(db, isTopLevel, writeMode, path, pathI, slotPtr) {
|
|
1182
|
+
if (writeMode === 0 /* READ_ONLY */)
|
|
1183
|
+
throw new WriteNotAllowedException;
|
|
1184
|
+
if (isTopLevel)
|
|
1185
|
+
throw new InvalidTopLevelTypeException;
|
|
1186
|
+
if (slotPtr.position === null)
|
|
1187
|
+
throw new CursorNotWriteableException;
|
|
1188
|
+
const position = slotPtr.position;
|
|
1189
|
+
switch (slotPtr.slot.tag) {
|
|
1190
|
+
case 0 /* NONE */: {
|
|
1191
|
+
const writer = db.core.writer();
|
|
1192
|
+
const arrayListStart = await db.core.length();
|
|
1193
|
+
await db.core.seek(arrayListStart);
|
|
1194
|
+
const arrayListPtr = arrayListStart + BigInt(LinkedArrayListHeader.LENGTH);
|
|
1195
|
+
await writer.write(new LinkedArrayListHeader(0, arrayListPtr, 0n).toBytes());
|
|
1196
|
+
await writer.write(new Uint8Array(LINKED_ARRAY_LIST_INDEX_BLOCK_SIZE));
|
|
1197
|
+
const nextSlotPtr = new SlotPointer(position, new Slot(arrayListStart, 3 /* LINKED_ARRAY_LIST */));
|
|
1198
|
+
await db.core.seek(position);
|
|
1199
|
+
await writer.write(nextSlotPtr.slot.toBytes());
|
|
1200
|
+
return db.readSlotPointer(writeMode, path, pathI + 1, nextSlotPtr);
|
|
1201
|
+
}
|
|
1202
|
+
case 3 /* LINKED_ARRAY_LIST */: {
|
|
1203
|
+
const reader = db.core.reader();
|
|
1204
|
+
const writer = db.core.writer();
|
|
1205
|
+
let arrayListStart = slotPtr.slot.value;
|
|
1206
|
+
if (db.txStart !== null) {
|
|
1207
|
+
if (arrayListStart < db.txStart) {
|
|
1208
|
+
await db.core.seek(arrayListStart);
|
|
1209
|
+
const headerBytes = new Uint8Array(LinkedArrayListHeader.LENGTH);
|
|
1210
|
+
await reader.readFully(headerBytes);
|
|
1211
|
+
const header = LinkedArrayListHeader.fromBytes(headerBytes);
|
|
1212
|
+
await db.core.seek(header.ptr);
|
|
1213
|
+
const arrayListIndexBlock = new Uint8Array(LINKED_ARRAY_LIST_INDEX_BLOCK_SIZE);
|
|
1214
|
+
await reader.readFully(arrayListIndexBlock);
|
|
1215
|
+
arrayListStart = await db.core.length();
|
|
1216
|
+
await db.core.seek(arrayListStart);
|
|
1217
|
+
const nextArrayListPtr = arrayListStart + BigInt(LinkedArrayListHeader.LENGTH);
|
|
1218
|
+
const newHeader = header.withPtr(nextArrayListPtr);
|
|
1219
|
+
await writer.write(newHeader.toBytes());
|
|
1220
|
+
await writer.write(arrayListIndexBlock);
|
|
1221
|
+
}
|
|
1222
|
+
} else if (db.header.tag === 2 /* ARRAY_LIST */) {
|
|
1223
|
+
throw new ExpectedTxStartException;
|
|
1224
|
+
}
|
|
1225
|
+
const nextSlotPtr = new SlotPointer(position, new Slot(arrayListStart, 3 /* LINKED_ARRAY_LIST */));
|
|
1226
|
+
await db.core.seek(position);
|
|
1227
|
+
await writer.write(nextSlotPtr.slot.toBytes());
|
|
1228
|
+
return db.readSlotPointer(writeMode, path, pathI + 1, nextSlotPtr);
|
|
1229
|
+
}
|
|
1230
|
+
default:
|
|
1231
|
+
throw new UnexpectedTagException;
|
|
1232
|
+
}
|
|
1233
|
+
}
|
|
1234
|
+
}
|
|
1235
|
+
|
|
1236
|
+
class LinkedArrayListGet {
|
|
1237
|
+
index;
|
|
1238
|
+
kind = "LinkedArrayListGet";
|
|
1239
|
+
constructor(index) {
|
|
1240
|
+
this.index = index;
|
|
1241
|
+
}
|
|
1242
|
+
async readSlotPointer(db, isTopLevel, writeMode, path, pathI, slotPtr) {
|
|
1243
|
+
switch (slotPtr.slot.tag) {
|
|
1244
|
+
case 0 /* NONE */:
|
|
1245
|
+
throw new KeyNotFoundException;
|
|
1246
|
+
case 3 /* LINKED_ARRAY_LIST */:
|
|
1247
|
+
break;
|
|
1248
|
+
default:
|
|
1249
|
+
throw new UnexpectedTagException;
|
|
1250
|
+
}
|
|
1251
|
+
let index = this.index;
|
|
1252
|
+
await db.core.seek(slotPtr.slot.value);
|
|
1253
|
+
const reader = db.core.reader();
|
|
1254
|
+
const headerBytes = new Uint8Array(LinkedArrayListHeader.LENGTH);
|
|
1255
|
+
await reader.readFully(headerBytes);
|
|
1256
|
+
const header = LinkedArrayListHeader.fromBytes(headerBytes);
|
|
1257
|
+
if (index >= header.size || index < -header.size) {
|
|
1258
|
+
throw new KeyNotFoundException;
|
|
1259
|
+
}
|
|
1260
|
+
const key = index < 0n ? header.size - bigAbs(index) : index;
|
|
1261
|
+
const finalSlotPtr = await db.readLinkedArrayListSlot(header.ptr, key, header.shift, writeMode, isTopLevel);
|
|
1262
|
+
return db.readSlotPointer(writeMode, path, pathI + 1, finalSlotPtr.slotPtr);
|
|
1263
|
+
}
|
|
1264
|
+
}
|
|
1265
|
+
|
|
1266
|
+
class LinkedArrayListAppend {
|
|
1267
|
+
kind = "LinkedArrayListAppend";
|
|
1268
|
+
async readSlotPointer(db, isTopLevel, writeMode, path, pathI, slotPtr) {
|
|
1269
|
+
if (writeMode === 0 /* READ_ONLY */)
|
|
1270
|
+
throw new WriteNotAllowedException;
|
|
1271
|
+
if (slotPtr.slot.tag !== 3 /* LINKED_ARRAY_LIST */)
|
|
1272
|
+
throw new UnexpectedTagException;
|
|
1273
|
+
const reader = db.core.reader();
|
|
1274
|
+
const nextArrayListStart = slotPtr.slot.value;
|
|
1275
|
+
await db.core.seek(nextArrayListStart);
|
|
1276
|
+
const headerBytes = new Uint8Array(LinkedArrayListHeader.LENGTH);
|
|
1277
|
+
await reader.readFully(headerBytes);
|
|
1278
|
+
const origHeader = LinkedArrayListHeader.fromBytes(headerBytes);
|
|
1279
|
+
const appendResult = await db.readLinkedArrayListSlotAppend(origHeader, writeMode, isTopLevel);
|
|
1280
|
+
const finalSlotPtr = await db.readSlotPointer(writeMode, path, pathI + 1, appendResult.slotPtr.slotPtr);
|
|
1281
|
+
const writer = db.core.writer();
|
|
1282
|
+
await db.core.seek(nextArrayListStart);
|
|
1283
|
+
await writer.write(appendResult.header.toBytes());
|
|
1284
|
+
return finalSlotPtr;
|
|
1285
|
+
}
|
|
1286
|
+
}
|
|
1287
|
+
|
|
1288
|
+
class LinkedArrayListSlice {
|
|
1289
|
+
offset;
|
|
1290
|
+
size;
|
|
1291
|
+
kind = "LinkedArrayListSlice";
|
|
1292
|
+
constructor(offset, size) {
|
|
1293
|
+
this.offset = offset;
|
|
1294
|
+
this.size = size;
|
|
1295
|
+
}
|
|
1296
|
+
async readSlotPointer(db, isTopLevel, writeMode, path, pathI, slotPtr) {
|
|
1297
|
+
if (writeMode === 0 /* READ_ONLY */)
|
|
1298
|
+
throw new WriteNotAllowedException;
|
|
1299
|
+
if (slotPtr.slot.tag !== 3 /* LINKED_ARRAY_LIST */)
|
|
1300
|
+
throw new UnexpectedTagException;
|
|
1301
|
+
const reader = db.core.reader();
|
|
1302
|
+
const nextArrayListStart = slotPtr.slot.value;
|
|
1303
|
+
await db.core.seek(nextArrayListStart);
|
|
1304
|
+
const headerBytes = new Uint8Array(LinkedArrayListHeader.LENGTH);
|
|
1305
|
+
await reader.readFully(headerBytes);
|
|
1306
|
+
const origHeader = LinkedArrayListHeader.fromBytes(headerBytes);
|
|
1307
|
+
const sliceHeader = await db.readLinkedArrayListSlice(origHeader, this.offset, this.size);
|
|
1308
|
+
const finalSlotPtr = await db.readSlotPointer(writeMode, path, pathI + 1, slotPtr);
|
|
1309
|
+
const writer = db.core.writer();
|
|
1310
|
+
await db.core.seek(nextArrayListStart);
|
|
1311
|
+
await writer.write(sliceHeader.toBytes());
|
|
1312
|
+
return finalSlotPtr;
|
|
1313
|
+
}
|
|
1314
|
+
}
|
|
1315
|
+
|
|
1316
|
+
class LinkedArrayListConcat {
|
|
1317
|
+
list;
|
|
1318
|
+
kind = "LinkedArrayListConcat";
|
|
1319
|
+
constructor(list) {
|
|
1320
|
+
this.list = list;
|
|
1321
|
+
}
|
|
1322
|
+
async readSlotPointer(db, isTopLevel, writeMode, path, pathI, slotPtr) {
|
|
1323
|
+
if (writeMode === 0 /* READ_ONLY */)
|
|
1324
|
+
throw new WriteNotAllowedException;
|
|
1325
|
+
if (slotPtr.slot.tag !== 3 /* LINKED_ARRAY_LIST */)
|
|
1326
|
+
throw new UnexpectedTagException;
|
|
1327
|
+
if (this.list.tag !== 3 /* LINKED_ARRAY_LIST */)
|
|
1328
|
+
throw new UnexpectedTagException;
|
|
1329
|
+
const reader = db.core.reader();
|
|
1330
|
+
const nextArrayListStart = slotPtr.slot.value;
|
|
1331
|
+
await db.core.seek(nextArrayListStart);
|
|
1332
|
+
const headerBytesA = new Uint8Array(LinkedArrayListHeader.LENGTH);
|
|
1333
|
+
await reader.readFully(headerBytesA);
|
|
1334
|
+
const headerA = LinkedArrayListHeader.fromBytes(headerBytesA);
|
|
1335
|
+
await db.core.seek(this.list.value);
|
|
1336
|
+
const headerBytesB = new Uint8Array(LinkedArrayListHeader.LENGTH);
|
|
1337
|
+
await reader.readFully(headerBytesB);
|
|
1338
|
+
const headerB = LinkedArrayListHeader.fromBytes(headerBytesB);
|
|
1339
|
+
const concatHeader = await db.readLinkedArrayListConcat(headerA, headerB);
|
|
1340
|
+
const finalSlotPtr = await db.readSlotPointer(writeMode, path, pathI + 1, slotPtr);
|
|
1341
|
+
const writer = db.core.writer();
|
|
1342
|
+
await db.core.seek(nextArrayListStart);
|
|
1343
|
+
await writer.write(concatHeader.toBytes());
|
|
1344
|
+
return finalSlotPtr;
|
|
1345
|
+
}
|
|
1346
|
+
}
|
|
1347
|
+
|
|
1348
|
+
class LinkedArrayListInsert {
|
|
1349
|
+
index;
|
|
1350
|
+
kind = "LinkedArrayListInsert";
|
|
1351
|
+
constructor(index) {
|
|
1352
|
+
this.index = index;
|
|
1353
|
+
}
|
|
1354
|
+
async readSlotPointer(db, isTopLevel, writeMode, path, pathI, slotPtr) {
|
|
1355
|
+
if (writeMode === 0 /* READ_ONLY */)
|
|
1356
|
+
throw new WriteNotAllowedException;
|
|
1357
|
+
if (slotPtr.slot.tag !== 3 /* LINKED_ARRAY_LIST */)
|
|
1358
|
+
throw new UnexpectedTagException;
|
|
1359
|
+
const reader = db.core.reader();
|
|
1360
|
+
const nextArrayListStart = slotPtr.slot.value;
|
|
1361
|
+
await db.core.seek(nextArrayListStart);
|
|
1362
|
+
const headerBytes = new Uint8Array(LinkedArrayListHeader.LENGTH);
|
|
1363
|
+
await reader.readFully(headerBytes);
|
|
1364
|
+
const origHeader = LinkedArrayListHeader.fromBytes(headerBytes);
|
|
1365
|
+
let index = this.index;
|
|
1366
|
+
if (index >= origHeader.size || index < -origHeader.size) {
|
|
1367
|
+
throw new KeyNotFoundException;
|
|
1368
|
+
}
|
|
1369
|
+
const key = index < 0n ? origHeader.size - bigAbs(index) : index;
|
|
1370
|
+
const headerA = await db.readLinkedArrayListSlice(origHeader, 0n, key);
|
|
1371
|
+
const headerB = await db.readLinkedArrayListSlice(origHeader, key, origHeader.size - key);
|
|
1372
|
+
const appendResult = await db.readLinkedArrayListSlotAppend(headerA, writeMode, isTopLevel);
|
|
1373
|
+
const concatHeader = await db.readLinkedArrayListConcat(appendResult.header, headerB);
|
|
1374
|
+
const nextSlotPtr = await db.readLinkedArrayListSlot(concatHeader.ptr, key, concatHeader.shift, 0 /* READ_ONLY */, isTopLevel);
|
|
1375
|
+
const finalSlotPtr = await db.readSlotPointer(writeMode, path, pathI + 1, nextSlotPtr.slotPtr);
|
|
1376
|
+
const writer = db.core.writer();
|
|
1377
|
+
await db.core.seek(nextArrayListStart);
|
|
1378
|
+
await writer.write(concatHeader.toBytes());
|
|
1379
|
+
return finalSlotPtr;
|
|
1380
|
+
}
|
|
1381
|
+
}
|
|
1382
|
+
|
|
1383
|
+
class LinkedArrayListRemove {
|
|
1384
|
+
index;
|
|
1385
|
+
kind = "LinkedArrayListRemove";
|
|
1386
|
+
constructor(index) {
|
|
1387
|
+
this.index = index;
|
|
1388
|
+
}
|
|
1389
|
+
async readSlotPointer(db, isTopLevel, writeMode, path, pathI, slotPtr) {
|
|
1390
|
+
if (writeMode === 0 /* READ_ONLY */)
|
|
1391
|
+
throw new WriteNotAllowedException;
|
|
1392
|
+
if (slotPtr.slot.tag !== 3 /* LINKED_ARRAY_LIST */)
|
|
1393
|
+
throw new UnexpectedTagException;
|
|
1394
|
+
const reader = db.core.reader();
|
|
1395
|
+
const nextArrayListStart = slotPtr.slot.value;
|
|
1396
|
+
await db.core.seek(nextArrayListStart);
|
|
1397
|
+
const headerBytes = new Uint8Array(LinkedArrayListHeader.LENGTH);
|
|
1398
|
+
await reader.readFully(headerBytes);
|
|
1399
|
+
const origHeader = LinkedArrayListHeader.fromBytes(headerBytes);
|
|
1400
|
+
let index = this.index;
|
|
1401
|
+
if (index >= origHeader.size || index < -origHeader.size) {
|
|
1402
|
+
throw new KeyNotFoundException;
|
|
1403
|
+
}
|
|
1404
|
+
const key = index < 0n ? origHeader.size - bigAbs(index) : index;
|
|
1405
|
+
const headerA = await db.readLinkedArrayListSlice(origHeader, 0n, key);
|
|
1406
|
+
const headerB = await db.readLinkedArrayListSlice(origHeader, key + 1n, origHeader.size - (key + 1n));
|
|
1407
|
+
const concatHeader = await db.readLinkedArrayListConcat(headerA, headerB);
|
|
1408
|
+
const nextSlotPtr = new SlotPointer(concatHeader.ptr, new Slot(nextArrayListStart, 3 /* LINKED_ARRAY_LIST */));
|
|
1409
|
+
const finalSlotPtr = await db.readSlotPointer(writeMode, path, pathI + 1, nextSlotPtr);
|
|
1410
|
+
const writer = db.core.writer();
|
|
1411
|
+
await db.core.seek(nextArrayListStart);
|
|
1412
|
+
await writer.write(concatHeader.toBytes());
|
|
1413
|
+
return finalSlotPtr;
|
|
1414
|
+
}
|
|
1415
|
+
}
|
|
1416
|
+
|
|
1417
|
+
class HashMapInit {
|
|
1418
|
+
counted;
|
|
1419
|
+
set;
|
|
1420
|
+
kind = "HashMapInit";
|
|
1421
|
+
constructor(counted = false, set = false) {
|
|
1422
|
+
this.counted = counted;
|
|
1423
|
+
this.set = set;
|
|
1424
|
+
}
|
|
1425
|
+
async readSlotPointer(db, isTopLevel, writeMode, path, pathI, slotPtr) {
|
|
1426
|
+
if (writeMode === 0 /* READ_ONLY */)
|
|
1427
|
+
throw new WriteNotAllowedException;
|
|
1428
|
+
const tag = this.counted ? this.set ? 13 /* COUNTED_HASH_SET */ : 12 /* COUNTED_HASH_MAP */ : this.set ? 11 /* HASH_SET */ : 4 /* HASH_MAP */;
|
|
1429
|
+
if (isTopLevel) {
|
|
1430
|
+
const writer = db.core.writer();
|
|
1431
|
+
if (db.header.tag === 0 /* NONE */) {
|
|
1432
|
+
await db.core.seek(BigInt(Header.LENGTH));
|
|
1433
|
+
if (this.counted) {
|
|
1434
|
+
await writer.writeLong(0n);
|
|
1435
|
+
}
|
|
1436
|
+
await writer.write(new Uint8Array(INDEX_BLOCK_SIZE));
|
|
1437
|
+
await db.core.seek(0n);
|
|
1438
|
+
db.header = db.header.withTag(tag);
|
|
1439
|
+
await writer.write(db.header.toBytes());
|
|
1440
|
+
}
|
|
1441
|
+
const nextSlotPtr = slotPtr.withSlot(slotPtr.slot.withTag(tag));
|
|
1442
|
+
return db.readSlotPointer(writeMode, path, pathI + 1, nextSlotPtr);
|
|
1443
|
+
}
|
|
1444
|
+
if (slotPtr.position === null)
|
|
1445
|
+
throw new CursorNotWriteableException;
|
|
1446
|
+
const position = slotPtr.position;
|
|
1447
|
+
switch (slotPtr.slot.tag) {
|
|
1448
|
+
case 0 /* NONE */: {
|
|
1449
|
+
const writer = db.core.writer();
|
|
1450
|
+
const mapStart = await db.core.length();
|
|
1451
|
+
await db.core.seek(mapStart);
|
|
1452
|
+
if (this.counted) {
|
|
1453
|
+
await writer.writeLong(0n);
|
|
1454
|
+
}
|
|
1455
|
+
await writer.write(new Uint8Array(INDEX_BLOCK_SIZE));
|
|
1456
|
+
const nextSlotPtr = new SlotPointer(position, new Slot(mapStart, tag));
|
|
1457
|
+
await db.core.seek(position);
|
|
1458
|
+
await writer.write(nextSlotPtr.slot.toBytes());
|
|
1459
|
+
return db.readSlotPointer(writeMode, path, pathI + 1, nextSlotPtr);
|
|
1460
|
+
}
|
|
1461
|
+
case 4 /* HASH_MAP */:
|
|
1462
|
+
case 11 /* HASH_SET */:
|
|
1463
|
+
case 12 /* COUNTED_HASH_MAP */:
|
|
1464
|
+
case 13 /* COUNTED_HASH_SET */: {
|
|
1465
|
+
if (this.counted) {
|
|
1466
|
+
switch (slotPtr.slot.tag) {
|
|
1467
|
+
case 12 /* COUNTED_HASH_MAP */:
|
|
1468
|
+
case 13 /* COUNTED_HASH_SET */:
|
|
1469
|
+
break;
|
|
1470
|
+
default:
|
|
1471
|
+
throw new UnexpectedTagException;
|
|
1472
|
+
}
|
|
1473
|
+
} else {
|
|
1474
|
+
switch (slotPtr.slot.tag) {
|
|
1475
|
+
case 4 /* HASH_MAP */:
|
|
1476
|
+
case 11 /* HASH_SET */:
|
|
1477
|
+
break;
|
|
1478
|
+
default:
|
|
1479
|
+
throw new UnexpectedTagException;
|
|
1480
|
+
}
|
|
1481
|
+
}
|
|
1482
|
+
const reader = db.core.reader();
|
|
1483
|
+
const writer = db.core.writer();
|
|
1484
|
+
let mapStart = slotPtr.slot.value;
|
|
1485
|
+
if (db.txStart !== null) {
|
|
1486
|
+
if (mapStart < db.txStart) {
|
|
1487
|
+
await db.core.seek(mapStart);
|
|
1488
|
+
let mapCountMaybe = null;
|
|
1489
|
+
if (this.counted) {
|
|
1490
|
+
mapCountMaybe = await reader.readLong();
|
|
1491
|
+
}
|
|
1492
|
+
const mapIndexBlock = new Uint8Array(INDEX_BLOCK_SIZE);
|
|
1493
|
+
await reader.readFully(mapIndexBlock);
|
|
1494
|
+
mapStart = await db.core.length();
|
|
1495
|
+
await db.core.seek(mapStart);
|
|
1496
|
+
if (mapCountMaybe !== null) {
|
|
1497
|
+
await writer.writeLong(mapCountMaybe);
|
|
1498
|
+
}
|
|
1499
|
+
await writer.write(mapIndexBlock);
|
|
1500
|
+
}
|
|
1501
|
+
} else if (db.header.tag === 2 /* ARRAY_LIST */) {
|
|
1502
|
+
throw new ExpectedTxStartException;
|
|
1503
|
+
}
|
|
1504
|
+
const nextSlotPtr = new SlotPointer(position, new Slot(mapStart, tag));
|
|
1505
|
+
await db.core.seek(position);
|
|
1506
|
+
await writer.write(nextSlotPtr.slot.toBytes());
|
|
1507
|
+
return db.readSlotPointer(writeMode, path, pathI + 1, nextSlotPtr);
|
|
1508
|
+
}
|
|
1509
|
+
default:
|
|
1510
|
+
throw new UnexpectedTagException;
|
|
1511
|
+
}
|
|
1512
|
+
}
|
|
1513
|
+
}
|
|
1514
|
+
|
|
1515
|
+
class HashMapGet {
|
|
1516
|
+
target;
|
|
1517
|
+
kind = "HashMapGet";
|
|
1518
|
+
constructor(target) {
|
|
1519
|
+
this.target = target;
|
|
1520
|
+
}
|
|
1521
|
+
async readSlotPointer(db, isTopLevel, writeMode, path, pathI, slotPtr) {
|
|
1522
|
+
let counted = false;
|
|
1523
|
+
switch (slotPtr.slot.tag) {
|
|
1524
|
+
case 0 /* NONE */:
|
|
1525
|
+
throw new KeyNotFoundException;
|
|
1526
|
+
case 4 /* HASH_MAP */:
|
|
1527
|
+
case 11 /* HASH_SET */:
|
|
1528
|
+
break;
|
|
1529
|
+
case 12 /* COUNTED_HASH_MAP */:
|
|
1530
|
+
case 13 /* COUNTED_HASH_SET */:
|
|
1531
|
+
counted = true;
|
|
1532
|
+
break;
|
|
1533
|
+
default:
|
|
1534
|
+
throw new UnexpectedTagException;
|
|
1535
|
+
}
|
|
1536
|
+
const indexPos = counted ? slotPtr.slot.value + 8n : slotPtr.slot.value;
|
|
1537
|
+
const hash = db.checkHash(this.target);
|
|
1538
|
+
const res = await db.readMapSlot(indexPos, hash, 0, writeMode, isTopLevel, this.target);
|
|
1539
|
+
if (writeMode === 1 /* READ_WRITE */ && counted && res.isEmpty) {
|
|
1540
|
+
const reader = db.core.reader();
|
|
1541
|
+
const writer = db.core.writer();
|
|
1542
|
+
await db.core.seek(slotPtr.slot.value);
|
|
1543
|
+
const mapCount = await reader.readLong();
|
|
1544
|
+
await db.core.seek(slotPtr.slot.value);
|
|
1545
|
+
await writer.writeLong(mapCount + 1n);
|
|
1546
|
+
}
|
|
1547
|
+
return db.readSlotPointer(writeMode, path, pathI + 1, res.slotPtr);
|
|
1548
|
+
}
|
|
1549
|
+
}
|
|
1550
|
+
|
|
1551
|
+
class HashMapRemove {
|
|
1552
|
+
hash;
|
|
1553
|
+
kind = "HashMapRemove";
|
|
1554
|
+
constructor(hash) {
|
|
1555
|
+
this.hash = hash;
|
|
1556
|
+
}
|
|
1557
|
+
async readSlotPointer(db, isTopLevel, writeMode, path, pathI, slotPtr) {
|
|
1558
|
+
if (writeMode === 0 /* READ_ONLY */)
|
|
1559
|
+
throw new WriteNotAllowedException;
|
|
1560
|
+
let counted = false;
|
|
1561
|
+
switch (slotPtr.slot.tag) {
|
|
1562
|
+
case 0 /* NONE */:
|
|
1563
|
+
throw new KeyNotFoundException;
|
|
1564
|
+
case 4 /* HASH_MAP */:
|
|
1565
|
+
case 11 /* HASH_SET */:
|
|
1566
|
+
break;
|
|
1567
|
+
case 12 /* COUNTED_HASH_MAP */:
|
|
1568
|
+
case 13 /* COUNTED_HASH_SET */:
|
|
1569
|
+
counted = true;
|
|
1570
|
+
break;
|
|
1571
|
+
default:
|
|
1572
|
+
throw new UnexpectedTagException;
|
|
1573
|
+
}
|
|
1574
|
+
const indexPos = counted ? slotPtr.slot.value + 8n : slotPtr.slot.value;
|
|
1575
|
+
const hash = db.checkHashBytes(this.hash);
|
|
1576
|
+
let keyFound = true;
|
|
1577
|
+
try {
|
|
1578
|
+
await db.removeMapSlot(indexPos, hash, 0, isTopLevel);
|
|
1579
|
+
} catch (e) {
|
|
1580
|
+
if (e instanceof KeyNotFoundException) {
|
|
1581
|
+
keyFound = false;
|
|
1582
|
+
} else {
|
|
1583
|
+
throw e;
|
|
1584
|
+
}
|
|
1585
|
+
}
|
|
1586
|
+
if (writeMode === 1 /* READ_WRITE */ && counted && keyFound) {
|
|
1587
|
+
const reader = db.core.reader();
|
|
1588
|
+
const writer = db.core.writer();
|
|
1589
|
+
await db.core.seek(slotPtr.slot.value);
|
|
1590
|
+
const mapCount = await reader.readLong();
|
|
1591
|
+
await db.core.seek(slotPtr.slot.value);
|
|
1592
|
+
await writer.writeLong(mapCount - 1n);
|
|
1593
|
+
}
|
|
1594
|
+
if (!keyFound)
|
|
1595
|
+
throw new KeyNotFoundException;
|
|
1596
|
+
return slotPtr;
|
|
1597
|
+
}
|
|
1598
|
+
}
|
|
1599
|
+
|
|
1600
|
+
class WriteData {
|
|
1601
|
+
data;
|
|
1602
|
+
kind = "WriteData";
|
|
1603
|
+
constructor(data) {
|
|
1604
|
+
this.data = data;
|
|
1605
|
+
}
|
|
1606
|
+
async readSlotPointer(db, isTopLevel, writeMode, path, pathI, slotPtr) {
|
|
1607
|
+
if (writeMode === 0 /* READ_ONLY */)
|
|
1608
|
+
throw new WriteNotAllowedException;
|
|
1609
|
+
if (slotPtr.position === null)
|
|
1610
|
+
throw new CursorNotWriteableException;
|
|
1611
|
+
const position = slotPtr.position;
|
|
1612
|
+
const writer = db.core.writer();
|
|
1613
|
+
const data = this.data;
|
|
1614
|
+
let slot;
|
|
1615
|
+
if (data === null) {
|
|
1616
|
+
slot = new Slot;
|
|
1617
|
+
} else if (data instanceof Slot) {
|
|
1618
|
+
slot = data;
|
|
1619
|
+
} else if (data instanceof Uint) {
|
|
1620
|
+
if (data.value < 0n) {
|
|
1621
|
+
throw new Error("Uint must not be negative");
|
|
1622
|
+
}
|
|
1623
|
+
slot = new Slot(data.value, 8 /* UINT */);
|
|
1624
|
+
} else if (data instanceof Int) {
|
|
1625
|
+
slot = new Slot(data.value, 9 /* INT */);
|
|
1626
|
+
} else if (data instanceof Float) {
|
|
1627
|
+
const buffer = new ArrayBuffer(8);
|
|
1628
|
+
const view = new DataView(buffer);
|
|
1629
|
+
view.setFloat64(0, data.value, false);
|
|
1630
|
+
const longValue = view.getBigInt64(0, false);
|
|
1631
|
+
slot = new Slot(longValue, 10 /* FLOAT */);
|
|
1632
|
+
} else if (data instanceof Bytes) {
|
|
1633
|
+
if (data.isShort()) {
|
|
1634
|
+
const buffer = new Uint8Array(8);
|
|
1635
|
+
buffer.set(data.value, 0);
|
|
1636
|
+
if (data.formatTag !== null) {
|
|
1637
|
+
buffer.set(data.formatTag, 6);
|
|
1638
|
+
}
|
|
1639
|
+
const view = new DataView(buffer.buffer);
|
|
1640
|
+
const longValue = view.getBigInt64(0, false);
|
|
1641
|
+
slot = new Slot(longValue, 7 /* SHORT_BYTES */, data.formatTag !== null);
|
|
1642
|
+
} else {
|
|
1643
|
+
const { WriteCursor: WriteCursor2 } = await Promise.resolve().then(() => (init_write_cursor(), exports_write_cursor));
|
|
1644
|
+
const nextCursor = new WriteCursor2(slotPtr, db);
|
|
1645
|
+
const cursorWriter = await nextCursor.writer();
|
|
1646
|
+
cursorWriter.formatTag = data.formatTag;
|
|
1647
|
+
await cursorWriter.write(data.value);
|
|
1648
|
+
await cursorWriter.finish();
|
|
1649
|
+
slot = cursorWriter.slot;
|
|
1650
|
+
}
|
|
1651
|
+
} else {
|
|
1652
|
+
throw new Error("Unknown data type");
|
|
1653
|
+
}
|
|
1654
|
+
if (slot.tag === 0 /* NONE */) {
|
|
1655
|
+
slot = slot.withFull(true);
|
|
1656
|
+
}
|
|
1657
|
+
await db.core.seek(position);
|
|
1658
|
+
await writer.write(slot.toBytes());
|
|
1659
|
+
const nextSlotPtr = new SlotPointer(slotPtr.position, slot);
|
|
1660
|
+
return db.readSlotPointer(writeMode, path, pathI + 1, nextSlotPtr);
|
|
1661
|
+
}
|
|
1662
|
+
}
|
|
1663
|
+
|
|
1664
|
+
class Context {
|
|
1665
|
+
fn;
|
|
1666
|
+
kind = "Context";
|
|
1667
|
+
constructor(fn) {
|
|
1668
|
+
this.fn = fn;
|
|
1669
|
+
}
|
|
1670
|
+
async readSlotPointer(db, isTopLevel, writeMode, path, pathI, slotPtr) {
|
|
1671
|
+
if (writeMode === 0 /* READ_ONLY */)
|
|
1672
|
+
throw new WriteNotAllowedException;
|
|
1673
|
+
if (pathI !== path.length - 1)
|
|
1674
|
+
throw new PathPartMustBeAtEndException;
|
|
1675
|
+
const { WriteCursor: WriteCursor2 } = await Promise.resolve().then(() => (init_write_cursor(), exports_write_cursor));
|
|
1676
|
+
const nextCursor = new WriteCursor2(slotPtr, db);
|
|
1677
|
+
try {
|
|
1678
|
+
await this.fn(nextCursor);
|
|
1679
|
+
} catch (e) {
|
|
1680
|
+
try {
|
|
1681
|
+
await db.truncate();
|
|
1682
|
+
} catch (_) {}
|
|
1683
|
+
throw e;
|
|
1684
|
+
}
|
|
1685
|
+
return nextCursor.slotPtr;
|
|
1686
|
+
}
|
|
1687
|
+
}
|
|
1688
|
+
|
|
1689
|
+
class HashMapGetResult {
|
|
1690
|
+
slotPtr;
|
|
1691
|
+
isEmpty;
|
|
1692
|
+
constructor(slotPtr, isEmpty) {
|
|
1693
|
+
this.slotPtr = slotPtr;
|
|
1694
|
+
this.isEmpty = isEmpty;
|
|
1695
|
+
}
|
|
1696
|
+
}
|
|
1697
|
+
|
|
1698
|
+
class ArrayListAppendResult {
|
|
1699
|
+
header;
|
|
1700
|
+
slotPtr;
|
|
1701
|
+
constructor(header, slotPtr) {
|
|
1702
|
+
this.header = header;
|
|
1703
|
+
this.slotPtr = slotPtr;
|
|
1704
|
+
}
|
|
1705
|
+
}
|
|
1706
|
+
|
|
1707
|
+
class LinkedArrayListAppendResult {
|
|
1708
|
+
header;
|
|
1709
|
+
slotPtr;
|
|
1710
|
+
constructor(header, slotPtr) {
|
|
1711
|
+
this.header = header;
|
|
1712
|
+
this.slotPtr = slotPtr;
|
|
1713
|
+
}
|
|
1714
|
+
}
|
|
1715
|
+
function arraysEqual(a, b) {
|
|
1716
|
+
if (a.length !== b.length)
|
|
1717
|
+
return false;
|
|
1718
|
+
for (let i = 0;i < a.length; i++) {
|
|
1719
|
+
if (a[i] !== b[i])
|
|
1720
|
+
return false;
|
|
1721
|
+
}
|
|
1722
|
+
return true;
|
|
1723
|
+
}
|
|
1724
|
+
function checkLong(n) {
|
|
1725
|
+
if (n < 0n) {
|
|
1726
|
+
throw new ExpectedUnsignedLongException;
|
|
1727
|
+
}
|
|
1728
|
+
return n;
|
|
1729
|
+
}
|
|
1730
|
+
function bigAbs(n) {
|
|
1731
|
+
return n < 0n ? -n : n;
|
|
1732
|
+
}
|
|
1733
|
+
function bigIntShiftRight(value, bits) {
|
|
1734
|
+
let result = 0n;
|
|
1735
|
+
for (let i = 0;i < value.length; i++) {
|
|
1736
|
+
result = result << 8n | BigInt(value[i]);
|
|
1737
|
+
}
|
|
1738
|
+
return result >> BigInt(bits);
|
|
1739
|
+
}
|
|
1740
|
+
|
|
1741
|
+
class Database3 {
|
|
1742
|
+
core;
|
|
1743
|
+
hasher;
|
|
1744
|
+
header;
|
|
1745
|
+
txStart = null;
|
|
1746
|
+
constructor(core, hasher) {
|
|
1747
|
+
this.core = core;
|
|
1748
|
+
this.hasher = hasher;
|
|
1749
|
+
}
|
|
1750
|
+
static async create(core, hasher) {
|
|
1751
|
+
const db = new Database3(core, hasher);
|
|
1752
|
+
await core.seek(0n);
|
|
1753
|
+
if (await core.length() === 0n) {
|
|
1754
|
+
db.header = new Header(hasher.id, hasher.digestLength, VERSION, 0 /* NONE */, MAGIC_NUMBER);
|
|
1755
|
+
await db.header.write(core);
|
|
1756
|
+
await core.flush();
|
|
1757
|
+
} else {
|
|
1758
|
+
db.header = await Header.read(core);
|
|
1759
|
+
db.header.validate();
|
|
1760
|
+
if (db.header.hashSize !== hasher.digestLength) {
|
|
1761
|
+
throw new InvalidHashSizeException;
|
|
1762
|
+
}
|
|
1763
|
+
await db.truncate();
|
|
1764
|
+
}
|
|
1765
|
+
return db;
|
|
1766
|
+
}
|
|
1767
|
+
async rootCursor() {
|
|
1768
|
+
const { WriteCursor: WriteCursor2 } = await Promise.resolve().then(() => (init_write_cursor(), exports_write_cursor));
|
|
1769
|
+
if (this.header.tag === 0 /* NONE */) {
|
|
1770
|
+
await this.core.seek(0n);
|
|
1771
|
+
this.header = await Header.read(this.core);
|
|
1772
|
+
}
|
|
1773
|
+
return new WriteCursor2(new SlotPointer(null, new Slot(BigInt(Header.LENGTH), this.header.tag)), this);
|
|
1774
|
+
}
|
|
1775
|
+
async freeze() {
|
|
1776
|
+
if (this.txStart !== null) {
|
|
1777
|
+
this.txStart = await this.core.length();
|
|
1778
|
+
} else {
|
|
1779
|
+
throw new ExpectedTxStartException;
|
|
1780
|
+
}
|
|
1781
|
+
}
|
|
1782
|
+
async truncate() {
|
|
1783
|
+
if (this.header.tag !== 2 /* ARRAY_LIST */)
|
|
1784
|
+
return;
|
|
1785
|
+
const rootCursor = await this.rootCursor();
|
|
1786
|
+
const listSize = await rootCursor.count();
|
|
1787
|
+
if (listSize === 0n)
|
|
1788
|
+
return;
|
|
1789
|
+
await this.core.seek(BigInt(Header.LENGTH + ArrayListHeader.LENGTH));
|
|
1790
|
+
const reader = this.core.reader();
|
|
1791
|
+
const headerFileSize = await reader.readLong();
|
|
1792
|
+
if (headerFileSize === 0n)
|
|
1793
|
+
return;
|
|
1794
|
+
const fileSize = await this.core.length();
|
|
1795
|
+
if (fileSize === headerFileSize)
|
|
1796
|
+
return;
|
|
1797
|
+
try {
|
|
1798
|
+
await this.core.setLength(headerFileSize);
|
|
1799
|
+
} catch (_) {}
|
|
1800
|
+
}
|
|
1801
|
+
checkHashBytes(hash) {
|
|
1802
|
+
if (hash.length !== this.header.hashSize) {
|
|
1803
|
+
throw new InvalidHashSizeException;
|
|
1804
|
+
}
|
|
1805
|
+
return hash;
|
|
1806
|
+
}
|
|
1807
|
+
checkHash(target) {
|
|
1808
|
+
return this.checkHashBytes(target.hash);
|
|
1809
|
+
}
|
|
1810
|
+
async readSlotPointer(writeMode, path, pathI, slotPtr) {
|
|
1811
|
+
if (pathI === path.length) {
|
|
1812
|
+
if (writeMode === 0 /* READ_ONLY */ && slotPtr.slot.tag === 0 /* NONE */) {
|
|
1813
|
+
throw new KeyNotFoundException;
|
|
1814
|
+
}
|
|
1815
|
+
return slotPtr;
|
|
1816
|
+
}
|
|
1817
|
+
const part = path[pathI];
|
|
1818
|
+
const isTopLevel = slotPtr.slot.value === BigInt(Header.LENGTH);
|
|
1819
|
+
const isTxStart = isTopLevel && this.header.tag === 2 /* ARRAY_LIST */ && this.txStart === null;
|
|
1820
|
+
if (isTxStart) {
|
|
1821
|
+
this.txStart = await this.core.length();
|
|
1822
|
+
}
|
|
1823
|
+
try {
|
|
1824
|
+
return await part.readSlotPointer(this, isTopLevel, writeMode, path, pathI, slotPtr);
|
|
1825
|
+
} finally {
|
|
1826
|
+
if (isTxStart) {
|
|
1827
|
+
this.txStart = null;
|
|
1828
|
+
}
|
|
1829
|
+
}
|
|
1830
|
+
}
|
|
1831
|
+
async readMapSlot(indexPos, keyHash, keyOffset, writeMode, isTopLevel, target) {
|
|
1832
|
+
if (keyOffset > this.header.hashSize * 8 / BIT_COUNT) {
|
|
1833
|
+
throw new KeyOffsetExceededException;
|
|
1834
|
+
}
|
|
1835
|
+
const reader = this.core.reader();
|
|
1836
|
+
const writer = this.core.writer();
|
|
1837
|
+
const i = Number(bigIntShiftRight(keyHash, keyOffset * BIT_COUNT) & MASK);
|
|
1838
|
+
const slotPos = indexPos + BigInt(Slot.LENGTH * i);
|
|
1839
|
+
await this.core.seek(slotPos);
|
|
1840
|
+
const slotBytes = new Uint8Array(Slot.LENGTH);
|
|
1841
|
+
await reader.readFully(slotBytes);
|
|
1842
|
+
const slot = Slot.fromBytes(slotBytes);
|
|
1843
|
+
const ptr = slot.value;
|
|
1844
|
+
switch (slot.tag) {
|
|
1845
|
+
case 0 /* NONE */: {
|
|
1846
|
+
switch (writeMode) {
|
|
1847
|
+
case 0 /* READ_ONLY */:
|
|
1848
|
+
throw new KeyNotFoundException;
|
|
1849
|
+
case 1 /* READ_WRITE */: {
|
|
1850
|
+
const hashPos = await this.core.length();
|
|
1851
|
+
await this.core.seek(hashPos);
|
|
1852
|
+
const keySlotPos = hashPos + BigInt(this.header.hashSize);
|
|
1853
|
+
const valueSlotPos = keySlotPos + BigInt(Slot.LENGTH);
|
|
1854
|
+
const kvPair = new KeyValuePair(new Slot, new Slot, keyHash);
|
|
1855
|
+
await writer.write(kvPair.toBytes());
|
|
1856
|
+
const nextSlot = new Slot(hashPos, 5 /* KV_PAIR */);
|
|
1857
|
+
await this.core.seek(slotPos);
|
|
1858
|
+
await writer.write(nextSlot.toBytes());
|
|
1859
|
+
let nextSlotPtr;
|
|
1860
|
+
if (target.kind === "kv_pair") {
|
|
1861
|
+
nextSlotPtr = new SlotPointer(slotPos, nextSlot);
|
|
1862
|
+
} else if (target.kind === "key") {
|
|
1863
|
+
nextSlotPtr = new SlotPointer(keySlotPos, kvPair.keySlot);
|
|
1864
|
+
} else {
|
|
1865
|
+
nextSlotPtr = new SlotPointer(valueSlotPos, kvPair.valueSlot);
|
|
1866
|
+
}
|
|
1867
|
+
return new HashMapGetResult(nextSlotPtr, true);
|
|
1868
|
+
}
|
|
1869
|
+
default:
|
|
1870
|
+
throw new UnreachableException;
|
|
1871
|
+
}
|
|
1872
|
+
}
|
|
1873
|
+
case 1 /* INDEX */: {
|
|
1874
|
+
let nextPtr = ptr;
|
|
1875
|
+
if (writeMode === 1 /* READ_WRITE */ && !isTopLevel) {
|
|
1876
|
+
if (this.txStart !== null) {
|
|
1877
|
+
if (nextPtr < this.txStart) {
|
|
1878
|
+
await this.core.seek(ptr);
|
|
1879
|
+
const indexBlock = new Uint8Array(INDEX_BLOCK_SIZE);
|
|
1880
|
+
await reader.readFully(indexBlock);
|
|
1881
|
+
nextPtr = await this.core.length();
|
|
1882
|
+
await this.core.seek(nextPtr);
|
|
1883
|
+
await writer.write(indexBlock);
|
|
1884
|
+
await this.core.seek(slotPos);
|
|
1885
|
+
await writer.write(new Slot(nextPtr, 1 /* INDEX */).toBytes());
|
|
1886
|
+
}
|
|
1887
|
+
} else if (this.header.tag === 2 /* ARRAY_LIST */) {
|
|
1888
|
+
throw new ExpectedTxStartException;
|
|
1889
|
+
}
|
|
1890
|
+
}
|
|
1891
|
+
return this.readMapSlot(nextPtr, keyHash, keyOffset + 1, writeMode, isTopLevel, target);
|
|
1892
|
+
}
|
|
1893
|
+
case 5 /* KV_PAIR */: {
|
|
1894
|
+
await this.core.seek(ptr);
|
|
1895
|
+
const kvPairBytes = new Uint8Array(KeyValuePair.length(this.header.hashSize));
|
|
1896
|
+
await reader.readFully(kvPairBytes);
|
|
1897
|
+
const kvPair = KeyValuePair.fromBytes(kvPairBytes, this.header.hashSize);
|
|
1898
|
+
if (arraysEqual(kvPair.hash, keyHash)) {
|
|
1899
|
+
if (writeMode === 1 /* READ_WRITE */ && !isTopLevel) {
|
|
1900
|
+
if (this.txStart !== null) {
|
|
1901
|
+
if (ptr < this.txStart) {
|
|
1902
|
+
const hashPos = await this.core.length();
|
|
1903
|
+
await this.core.seek(hashPos);
|
|
1904
|
+
const keySlotPos2 = hashPos + BigInt(this.header.hashSize);
|
|
1905
|
+
const valueSlotPos2 = keySlotPos2 + BigInt(Slot.LENGTH);
|
|
1906
|
+
await writer.write(kvPair.toBytes());
|
|
1907
|
+
const nextSlot = new Slot(hashPos, 5 /* KV_PAIR */);
|
|
1908
|
+
await this.core.seek(slotPos);
|
|
1909
|
+
await writer.write(nextSlot.toBytes());
|
|
1910
|
+
let nextSlotPtr2;
|
|
1911
|
+
if (target.kind === "kv_pair") {
|
|
1912
|
+
nextSlotPtr2 = new SlotPointer(slotPos, nextSlot);
|
|
1913
|
+
} else if (target.kind === "key") {
|
|
1914
|
+
nextSlotPtr2 = new SlotPointer(keySlotPos2, kvPair.keySlot);
|
|
1915
|
+
} else {
|
|
1916
|
+
nextSlotPtr2 = new SlotPointer(valueSlotPos2, kvPair.valueSlot);
|
|
1917
|
+
}
|
|
1918
|
+
return new HashMapGetResult(nextSlotPtr2, false);
|
|
1919
|
+
}
|
|
1920
|
+
} else if (this.header.tag === 2 /* ARRAY_LIST */) {
|
|
1921
|
+
throw new ExpectedTxStartException;
|
|
1922
|
+
}
|
|
1923
|
+
}
|
|
1924
|
+
const keySlotPos = ptr + BigInt(this.header.hashSize);
|
|
1925
|
+
const valueSlotPos = keySlotPos + BigInt(Slot.LENGTH);
|
|
1926
|
+
let nextSlotPtr;
|
|
1927
|
+
if (target.kind === "kv_pair") {
|
|
1928
|
+
nextSlotPtr = new SlotPointer(slotPos, slot);
|
|
1929
|
+
} else if (target.kind === "key") {
|
|
1930
|
+
nextSlotPtr = new SlotPointer(keySlotPos, kvPair.keySlot);
|
|
1931
|
+
} else {
|
|
1932
|
+
nextSlotPtr = new SlotPointer(valueSlotPos, kvPair.valueSlot);
|
|
1933
|
+
}
|
|
1934
|
+
return new HashMapGetResult(nextSlotPtr, false);
|
|
1935
|
+
} else {
|
|
1936
|
+
switch (writeMode) {
|
|
1937
|
+
case 0 /* READ_ONLY */:
|
|
1938
|
+
throw new KeyNotFoundException;
|
|
1939
|
+
case 1 /* READ_WRITE */: {
|
|
1940
|
+
if (keyOffset + 1 >= this.header.hashSize * 8 / BIT_COUNT) {
|
|
1941
|
+
throw new KeyOffsetExceededException;
|
|
1942
|
+
}
|
|
1943
|
+
const nextI = Number(bigIntShiftRight(kvPair.hash, (keyOffset + 1) * BIT_COUNT) & MASK);
|
|
1944
|
+
const nextIndexPos = await this.core.length();
|
|
1945
|
+
await this.core.seek(nextIndexPos);
|
|
1946
|
+
await writer.write(new Uint8Array(INDEX_BLOCK_SIZE));
|
|
1947
|
+
await this.core.seek(nextIndexPos + BigInt(Slot.LENGTH * nextI));
|
|
1948
|
+
await writer.write(slot.toBytes());
|
|
1949
|
+
const res = await this.readMapSlot(nextIndexPos, keyHash, keyOffset + 1, writeMode, isTopLevel, target);
|
|
1950
|
+
await this.core.seek(slotPos);
|
|
1951
|
+
await writer.write(new Slot(nextIndexPos, 1 /* INDEX */).toBytes());
|
|
1952
|
+
return res;
|
|
1953
|
+
}
|
|
1954
|
+
default:
|
|
1955
|
+
throw new UnreachableException;
|
|
1956
|
+
}
|
|
1957
|
+
}
|
|
1958
|
+
}
|
|
1959
|
+
default:
|
|
1960
|
+
throw new UnexpectedTagException;
|
|
1961
|
+
}
|
|
1962
|
+
}
|
|
1963
|
+
async removeMapSlot(indexPos, keyHash, keyOffset, isTopLevel) {
|
|
1964
|
+
if (keyOffset > this.header.hashSize * 8 / BIT_COUNT) {
|
|
1965
|
+
throw new KeyOffsetExceededException;
|
|
1966
|
+
}
|
|
1967
|
+
const reader = this.core.reader();
|
|
1968
|
+
const writer = this.core.writer();
|
|
1969
|
+
const slotBlock = new Array(SLOT_COUNT);
|
|
1970
|
+
await this.core.seek(indexPos);
|
|
1971
|
+
const indexBlock = new Uint8Array(INDEX_BLOCK_SIZE);
|
|
1972
|
+
await reader.readFully(indexBlock);
|
|
1973
|
+
for (let i2 = 0;i2 < SLOT_COUNT; i2++) {
|
|
1974
|
+
const slotBytes = indexBlock.slice(i2 * Slot.LENGTH, (i2 + 1) * Slot.LENGTH);
|
|
1975
|
+
slotBlock[i2] = Slot.fromBytes(slotBytes);
|
|
1976
|
+
}
|
|
1977
|
+
const i = Number(bigIntShiftRight(keyHash, keyOffset * BIT_COUNT) & MASK);
|
|
1978
|
+
const slotPos = indexPos + BigInt(Slot.LENGTH * i);
|
|
1979
|
+
const slot = slotBlock[i];
|
|
1980
|
+
let nextSlot;
|
|
1981
|
+
switch (slot.tag) {
|
|
1982
|
+
case 0 /* NONE */:
|
|
1983
|
+
throw new KeyNotFoundException;
|
|
1984
|
+
case 1 /* INDEX */:
|
|
1985
|
+
nextSlot = await this.removeMapSlot(slot.value, keyHash, keyOffset + 1, isTopLevel);
|
|
1986
|
+
break;
|
|
1987
|
+
case 5 /* KV_PAIR */: {
|
|
1988
|
+
await this.core.seek(slot.value);
|
|
1989
|
+
const kvPairBytes = new Uint8Array(KeyValuePair.length(this.header.hashSize));
|
|
1990
|
+
await reader.readFully(kvPairBytes);
|
|
1991
|
+
const kvPair = KeyValuePair.fromBytes(kvPairBytes, this.header.hashSize);
|
|
1992
|
+
if (arraysEqual(kvPair.hash, keyHash)) {
|
|
1993
|
+
nextSlot = new Slot;
|
|
1994
|
+
} else {
|
|
1995
|
+
throw new KeyNotFoundException;
|
|
1996
|
+
}
|
|
1997
|
+
break;
|
|
1998
|
+
}
|
|
1999
|
+
default:
|
|
2000
|
+
throw new UnexpectedTagException;
|
|
2001
|
+
}
|
|
2002
|
+
if (keyOffset === 0) {
|
|
2003
|
+
await this.core.seek(slotPos);
|
|
2004
|
+
await writer.write(nextSlot.toBytes());
|
|
2005
|
+
return new Slot(indexPos, 1 /* INDEX */);
|
|
2006
|
+
}
|
|
2007
|
+
let slotToReturnMaybe = new Slot;
|
|
2008
|
+
slotBlock[i] = nextSlot;
|
|
2009
|
+
for (const blockSlot of slotBlock) {
|
|
2010
|
+
if (blockSlot.tag === 0 /* NONE */)
|
|
2011
|
+
continue;
|
|
2012
|
+
if (slotToReturnMaybe !== null) {
|
|
2013
|
+
if (slotToReturnMaybe.tag !== 0 /* NONE */) {
|
|
2014
|
+
slotToReturnMaybe = null;
|
|
2015
|
+
break;
|
|
2016
|
+
}
|
|
2017
|
+
}
|
|
2018
|
+
slotToReturnMaybe = blockSlot;
|
|
2019
|
+
}
|
|
2020
|
+
if (slotToReturnMaybe !== null) {
|
|
2021
|
+
switch (slotToReturnMaybe.tag) {
|
|
2022
|
+
case 0 /* NONE */:
|
|
2023
|
+
case 5 /* KV_PAIR */:
|
|
2024
|
+
return slotToReturnMaybe;
|
|
2025
|
+
default:
|
|
2026
|
+
break;
|
|
2027
|
+
}
|
|
2028
|
+
}
|
|
2029
|
+
if (!isTopLevel) {
|
|
2030
|
+
if (this.txStart !== null) {
|
|
2031
|
+
if (indexPos < this.txStart) {
|
|
2032
|
+
const nextIndexPos = await this.core.length();
|
|
2033
|
+
await this.core.seek(nextIndexPos);
|
|
2034
|
+
await writer.write(indexBlock);
|
|
2035
|
+
const nextSlotPos = nextIndexPos + BigInt(Slot.LENGTH * i);
|
|
2036
|
+
await this.core.seek(nextSlotPos);
|
|
2037
|
+
await writer.write(nextSlot.toBytes());
|
|
2038
|
+
return new Slot(nextIndexPos, 1 /* INDEX */);
|
|
2039
|
+
}
|
|
2040
|
+
} else if (this.header.tag === 2 /* ARRAY_LIST */) {
|
|
2041
|
+
throw new ExpectedTxStartException;
|
|
2042
|
+
}
|
|
2043
|
+
}
|
|
2044
|
+
await this.core.seek(slotPos);
|
|
2045
|
+
await writer.write(nextSlot.toBytes());
|
|
2046
|
+
return new Slot(indexPos, 1 /* INDEX */);
|
|
2047
|
+
}
|
|
2048
|
+
async readArrayListSlotAppend(header, writeMode, isTopLevel) {
|
|
2049
|
+
const writer = this.core.writer();
|
|
2050
|
+
let indexPos = header.ptr;
|
|
2051
|
+
const key = header.size;
|
|
2052
|
+
const prevShift = key < BigInt(SLOT_COUNT) ? 0 : Math.floor(Math.log(Number(key - 1n)) / Math.log(SLOT_COUNT));
|
|
2053
|
+
const nextShift = key < BigInt(SLOT_COUNT) ? 0 : Math.floor(Math.log(Number(key)) / Math.log(SLOT_COUNT));
|
|
2054
|
+
if (prevShift !== nextShift) {
|
|
2055
|
+
const nextIndexPos = await this.core.length();
|
|
2056
|
+
await this.core.seek(nextIndexPos);
|
|
2057
|
+
await writer.write(new Uint8Array(INDEX_BLOCK_SIZE));
|
|
2058
|
+
await this.core.seek(nextIndexPos);
|
|
2059
|
+
await writer.write(new Slot(indexPos, 1 /* INDEX */).toBytes());
|
|
2060
|
+
indexPos = nextIndexPos;
|
|
2061
|
+
}
|
|
2062
|
+
const slotPtr = await this.readArrayListSlot(indexPos, key, nextShift, writeMode, isTopLevel);
|
|
2063
|
+
return new ArrayListAppendResult(new ArrayListHeader(indexPos, header.size + 1n), slotPtr);
|
|
2064
|
+
}
|
|
2065
|
+
async readArrayListSlot(indexPos, key, shift, writeMode, isTopLevel) {
|
|
2066
|
+
if (shift >= MAX_BRANCH_LENGTH)
|
|
2067
|
+
throw new MaxShiftExceededException;
|
|
2068
|
+
const reader = this.core.reader();
|
|
2069
|
+
const i = Number(key >> BigInt(shift * BIT_COUNT) & MASK);
|
|
2070
|
+
const slotPos = indexPos + BigInt(Slot.LENGTH * i);
|
|
2071
|
+
await this.core.seek(slotPos);
|
|
2072
|
+
const slotBytes = new Uint8Array(Slot.LENGTH);
|
|
2073
|
+
await reader.readFully(slotBytes);
|
|
2074
|
+
const slot = Slot.fromBytes(slotBytes);
|
|
2075
|
+
if (shift === 0) {
|
|
2076
|
+
return new SlotPointer(slotPos, slot);
|
|
2077
|
+
}
|
|
2078
|
+
const ptr = slot.value;
|
|
2079
|
+
switch (slot.tag) {
|
|
2080
|
+
case 0 /* NONE */: {
|
|
2081
|
+
switch (writeMode) {
|
|
2082
|
+
case 0 /* READ_ONLY */:
|
|
2083
|
+
throw new KeyNotFoundException;
|
|
2084
|
+
case 1 /* READ_WRITE */: {
|
|
2085
|
+
const writer = this.core.writer();
|
|
2086
|
+
const nextIndexPos = await this.core.length();
|
|
2087
|
+
await this.core.seek(nextIndexPos);
|
|
2088
|
+
await writer.write(new Uint8Array(INDEX_BLOCK_SIZE));
|
|
2089
|
+
if (isTopLevel) {
|
|
2090
|
+
const fileSize = await this.core.length();
|
|
2091
|
+
await this.core.seek(BigInt(Header.LENGTH + ArrayListHeader.LENGTH));
|
|
2092
|
+
await writer.writeLong(fileSize);
|
|
2093
|
+
}
|
|
2094
|
+
await this.core.seek(slotPos);
|
|
2095
|
+
await writer.write(new Slot(nextIndexPos, 1 /* INDEX */).toBytes());
|
|
2096
|
+
return this.readArrayListSlot(nextIndexPos, key, shift - 1, writeMode, isTopLevel);
|
|
2097
|
+
}
|
|
2098
|
+
default:
|
|
2099
|
+
throw new UnreachableException;
|
|
2100
|
+
}
|
|
2101
|
+
}
|
|
2102
|
+
case 1 /* INDEX */: {
|
|
2103
|
+
let nextPtr = ptr;
|
|
2104
|
+
if (writeMode === 1 /* READ_WRITE */ && !isTopLevel) {
|
|
2105
|
+
if (this.txStart !== null) {
|
|
2106
|
+
if (nextPtr < this.txStart) {
|
|
2107
|
+
await this.core.seek(ptr);
|
|
2108
|
+
const indexBlock = new Uint8Array(INDEX_BLOCK_SIZE);
|
|
2109
|
+
await reader.readFully(indexBlock);
|
|
2110
|
+
const writer = this.core.writer();
|
|
2111
|
+
nextPtr = await this.core.length();
|
|
2112
|
+
await this.core.seek(nextPtr);
|
|
2113
|
+
await writer.write(indexBlock);
|
|
2114
|
+
await this.core.seek(slotPos);
|
|
2115
|
+
await writer.write(new Slot(nextPtr, 1 /* INDEX */).toBytes());
|
|
2116
|
+
}
|
|
2117
|
+
} else if (this.header.tag === 2 /* ARRAY_LIST */) {
|
|
2118
|
+
throw new ExpectedTxStartException;
|
|
2119
|
+
}
|
|
2120
|
+
}
|
|
2121
|
+
return this.readArrayListSlot(nextPtr, key, shift - 1, writeMode, isTopLevel);
|
|
2122
|
+
}
|
|
2123
|
+
default:
|
|
2124
|
+
throw new UnexpectedTagException;
|
|
2125
|
+
}
|
|
2126
|
+
}
|
|
2127
|
+
async readArrayListSlice(header, size) {
|
|
2128
|
+
const reader = this.core.reader();
|
|
2129
|
+
if (size > header.size || size < 0n) {
|
|
2130
|
+
throw new KeyNotFoundException;
|
|
2131
|
+
}
|
|
2132
|
+
const prevShift = header.size < BigInt(SLOT_COUNT + 1) ? 0 : Math.floor(Math.log(Number(header.size - 1n)) / Math.log(SLOT_COUNT));
|
|
2133
|
+
const nextShift = size < BigInt(SLOT_COUNT + 1) ? 0 : Math.floor(Math.log(Number(size - 1n)) / Math.log(SLOT_COUNT));
|
|
2134
|
+
if (prevShift === nextShift) {
|
|
2135
|
+
return new ArrayListHeader(header.ptr, size);
|
|
2136
|
+
} else {
|
|
2137
|
+
let shift = prevShift;
|
|
2138
|
+
let indexPos = header.ptr;
|
|
2139
|
+
while (shift > nextShift) {
|
|
2140
|
+
await this.core.seek(indexPos);
|
|
2141
|
+
const slotBytes = new Uint8Array(Slot.LENGTH);
|
|
2142
|
+
await reader.readFully(slotBytes);
|
|
2143
|
+
const slot = Slot.fromBytes(slotBytes);
|
|
2144
|
+
shift -= 1;
|
|
2145
|
+
indexPos = slot.value;
|
|
2146
|
+
}
|
|
2147
|
+
return new ArrayListHeader(indexPos, size);
|
|
2148
|
+
}
|
|
2149
|
+
}
|
|
2150
|
+
async readLinkedArrayListSlotAppend(header, writeMode, isTopLevel) {
|
|
2151
|
+
const writer = this.core.writer();
|
|
2152
|
+
let ptr = header.ptr;
|
|
2153
|
+
const key = header.size;
|
|
2154
|
+
let shift = header.shift;
|
|
2155
|
+
let slotPtr;
|
|
2156
|
+
try {
|
|
2157
|
+
slotPtr = await this.readLinkedArrayListSlot(ptr, key, shift, writeMode, isTopLevel);
|
|
2158
|
+
} catch (e) {
|
|
2159
|
+
if (e instanceof NoAvailableSlotsException) {
|
|
2160
|
+
const nextPtr = await this.core.length();
|
|
2161
|
+
await this.core.seek(nextPtr);
|
|
2162
|
+
await writer.write(new Uint8Array(LINKED_ARRAY_LIST_INDEX_BLOCK_SIZE));
|
|
2163
|
+
await this.core.seek(nextPtr);
|
|
2164
|
+
await writer.write(new LinkedArrayListSlot2(header.size, new Slot(ptr, 1 /* INDEX */, true)).toBytes());
|
|
2165
|
+
ptr = nextPtr;
|
|
2166
|
+
shift += 1;
|
|
2167
|
+
slotPtr = await this.readLinkedArrayListSlot(ptr, key, shift, writeMode, isTopLevel);
|
|
2168
|
+
} else {
|
|
2169
|
+
throw e;
|
|
2170
|
+
}
|
|
2171
|
+
}
|
|
2172
|
+
const newSlot = new Slot(0n, 0 /* NONE */, true);
|
|
2173
|
+
slotPtr = slotPtr.withSlotPointer(slotPtr.slotPtr.withSlot(newSlot));
|
|
2174
|
+
if (slotPtr.slotPtr.position === null)
|
|
2175
|
+
throw new CursorNotWriteableException;
|
|
2176
|
+
const position = slotPtr.slotPtr.position;
|
|
2177
|
+
await this.core.seek(position);
|
|
2178
|
+
await writer.write(new LinkedArrayListSlot2(0n, newSlot).toBytes());
|
|
2179
|
+
if (header.size < BigInt(SLOT_COUNT) && shift > 0) {
|
|
2180
|
+
throw new MustSetNewSlotsToFullException;
|
|
2181
|
+
}
|
|
2182
|
+
return new LinkedArrayListAppendResult(new LinkedArrayListHeader(shift, ptr, header.size + 1n), slotPtr);
|
|
2183
|
+
}
|
|
2184
|
+
static blockLeafCount(block, shift, i) {
|
|
2185
|
+
let n = 0n;
|
|
2186
|
+
if (shift === 0) {
|
|
2187
|
+
for (let blockI = 0;blockI < block.length; blockI++) {
|
|
2188
|
+
const blockSlot = block[blockI];
|
|
2189
|
+
if (!blockSlot.slot.empty() || blockI === i) {
|
|
2190
|
+
n += 1n;
|
|
2191
|
+
}
|
|
2192
|
+
}
|
|
2193
|
+
} else {
|
|
2194
|
+
for (const blockSlot of block) {
|
|
2195
|
+
n += blockSlot.size;
|
|
2196
|
+
}
|
|
2197
|
+
}
|
|
2198
|
+
return n;
|
|
2199
|
+
}
|
|
2200
|
+
static slotLeafCount(slot, shift) {
|
|
2201
|
+
if (shift === 0) {
|
|
2202
|
+
if (slot.slot.empty()) {
|
|
2203
|
+
return 0n;
|
|
2204
|
+
} else {
|
|
2205
|
+
return 1n;
|
|
2206
|
+
}
|
|
2207
|
+
} else {
|
|
2208
|
+
return slot.size;
|
|
2209
|
+
}
|
|
2210
|
+
}
|
|
2211
|
+
static keyAndIndexForLinkedArrayList(slotBlock, key, shift) {
|
|
2212
|
+
let nextKey = key;
|
|
2213
|
+
let i = 0;
|
|
2214
|
+
const maxLeafCount = shift === 0 ? 1n : BigInt(Math.pow(SLOT_COUNT, shift));
|
|
2215
|
+
while (true) {
|
|
2216
|
+
const slotLeafCount = Database3.slotLeafCount(slotBlock[i], shift);
|
|
2217
|
+
if (nextKey === slotLeafCount) {
|
|
2218
|
+
if (slotLeafCount === maxLeafCount || slotBlock[i].slot.full) {
|
|
2219
|
+
if (i < SLOT_COUNT - 1) {
|
|
2220
|
+
nextKey -= slotLeafCount;
|
|
2221
|
+
i += 1;
|
|
2222
|
+
} else {
|
|
2223
|
+
return null;
|
|
2224
|
+
}
|
|
2225
|
+
}
|
|
2226
|
+
break;
|
|
2227
|
+
} else if (nextKey < slotLeafCount) {
|
|
2228
|
+
break;
|
|
2229
|
+
} else if (i < SLOT_COUNT - 1) {
|
|
2230
|
+
nextKey -= slotLeafCount;
|
|
2231
|
+
i += 1;
|
|
2232
|
+
} else {
|
|
2233
|
+
return null;
|
|
2234
|
+
}
|
|
2235
|
+
}
|
|
2236
|
+
return { key: nextKey, index: i };
|
|
2237
|
+
}
|
|
2238
|
+
async readLinkedArrayListSlot(indexPos, key, shift, writeMode, isTopLevel) {
|
|
2239
|
+
if (shift >= MAX_BRANCH_LENGTH)
|
|
2240
|
+
throw new MaxShiftExceededException;
|
|
2241
|
+
const reader = this.core.reader();
|
|
2242
|
+
const writer = this.core.writer();
|
|
2243
|
+
const slotBlock = new Array(SLOT_COUNT);
|
|
2244
|
+
await this.core.seek(indexPos);
|
|
2245
|
+
const indexBlock = new Uint8Array(LINKED_ARRAY_LIST_INDEX_BLOCK_SIZE);
|
|
2246
|
+
await reader.readFully(indexBlock);
|
|
2247
|
+
for (let i2 = 0;i2 < SLOT_COUNT; i2++) {
|
|
2248
|
+
const slotBytes = indexBlock.slice(i2 * LinkedArrayListSlot2.LENGTH, (i2 + 1) * LinkedArrayListSlot2.LENGTH);
|
|
2249
|
+
slotBlock[i2] = LinkedArrayListSlot2.fromBytes(slotBytes);
|
|
2250
|
+
}
|
|
2251
|
+
const keyAndIndex = Database3.keyAndIndexForLinkedArrayList(slotBlock, key, shift);
|
|
2252
|
+
if (keyAndIndex === null)
|
|
2253
|
+
throw new NoAvailableSlotsException;
|
|
2254
|
+
const nextKey = keyAndIndex.key;
|
|
2255
|
+
const i = keyAndIndex.index;
|
|
2256
|
+
const slot = slotBlock[i];
|
|
2257
|
+
const slotPos = indexPos + BigInt(LinkedArrayListSlot2.LENGTH * i);
|
|
2258
|
+
if (shift === 0) {
|
|
2259
|
+
const leafCount = Database3.blockLeafCount(slotBlock, shift, i);
|
|
2260
|
+
return new LinkedArrayListSlotPointer(new SlotPointer(slotPos, slot.slot), leafCount);
|
|
2261
|
+
}
|
|
2262
|
+
const ptr = slot.slot.value;
|
|
2263
|
+
switch (slot.slot.tag) {
|
|
2264
|
+
case 0 /* NONE */: {
|
|
2265
|
+
switch (writeMode) {
|
|
2266
|
+
case 0 /* READ_ONLY */:
|
|
2267
|
+
throw new KeyNotFoundException;
|
|
2268
|
+
case 1 /* READ_WRITE */: {
|
|
2269
|
+
const nextIndexPos = await this.core.length();
|
|
2270
|
+
await this.core.seek(nextIndexPos);
|
|
2271
|
+
await writer.write(new Uint8Array(LINKED_ARRAY_LIST_INDEX_BLOCK_SIZE));
|
|
2272
|
+
const nextSlotPtr = await this.readLinkedArrayListSlot(nextIndexPos, nextKey, shift - 1, writeMode, isTopLevel);
|
|
2273
|
+
slotBlock[i] = slotBlock[i].withSize(nextSlotPtr.leafCount);
|
|
2274
|
+
const leafCount = Database3.blockLeafCount(slotBlock, shift, i);
|
|
2275
|
+
await this.core.seek(slotPos);
|
|
2276
|
+
await writer.write(new LinkedArrayListSlot2(nextSlotPtr.leafCount, new Slot(nextIndexPos, 1 /* INDEX */)).toBytes());
|
|
2277
|
+
return new LinkedArrayListSlotPointer(nextSlotPtr.slotPtr, leafCount);
|
|
2278
|
+
}
|
|
2279
|
+
default:
|
|
2280
|
+
throw new UnreachableException;
|
|
2281
|
+
}
|
|
2282
|
+
}
|
|
2283
|
+
case 1 /* INDEX */: {
|
|
2284
|
+
let nextPtr = ptr;
|
|
2285
|
+
if (writeMode === 1 /* READ_WRITE */ && !isTopLevel) {
|
|
2286
|
+
if (this.txStart !== null) {
|
|
2287
|
+
if (nextPtr < this.txStart) {
|
|
2288
|
+
await this.core.seek(ptr);
|
|
2289
|
+
const indexBlockCopy = new Uint8Array(LINKED_ARRAY_LIST_INDEX_BLOCK_SIZE);
|
|
2290
|
+
await reader.readFully(indexBlockCopy);
|
|
2291
|
+
nextPtr = await this.core.length();
|
|
2292
|
+
await this.core.seek(nextPtr);
|
|
2293
|
+
await writer.write(indexBlockCopy);
|
|
2294
|
+
}
|
|
2295
|
+
} else if (this.header.tag === 2 /* ARRAY_LIST */) {
|
|
2296
|
+
throw new ExpectedTxStartException;
|
|
2297
|
+
}
|
|
2298
|
+
}
|
|
2299
|
+
const nextSlotPtr = await this.readLinkedArrayListSlot(nextPtr, nextKey, shift - 1, writeMode, isTopLevel);
|
|
2300
|
+
slotBlock[i] = slotBlock[i].withSize(nextSlotPtr.leafCount);
|
|
2301
|
+
const leafCount = Database3.blockLeafCount(slotBlock, shift, i);
|
|
2302
|
+
if (writeMode === 1 /* READ_WRITE */ && !isTopLevel) {
|
|
2303
|
+
await this.core.seek(slotPos);
|
|
2304
|
+
await writer.write(new LinkedArrayListSlot2(nextSlotPtr.leafCount, new Slot(nextPtr, 1 /* INDEX */)).toBytes());
|
|
2305
|
+
}
|
|
2306
|
+
return new LinkedArrayListSlotPointer(nextSlotPtr.slotPtr, leafCount);
|
|
2307
|
+
}
|
|
2308
|
+
default:
|
|
2309
|
+
throw new UnexpectedTagException;
|
|
2310
|
+
}
|
|
2311
|
+
}
|
|
2312
|
+
async readLinkedArrayListBlocks(indexPos, key, shift, blocks) {
|
|
2313
|
+
const reader = this.core.reader();
|
|
2314
|
+
const slotBlock = new Array(SLOT_COUNT);
|
|
2315
|
+
await this.core.seek(indexPos);
|
|
2316
|
+
const indexBlock = new Uint8Array(LINKED_ARRAY_LIST_INDEX_BLOCK_SIZE);
|
|
2317
|
+
await reader.readFully(indexBlock);
|
|
2318
|
+
for (let i2 = 0;i2 < SLOT_COUNT; i2++) {
|
|
2319
|
+
const slotBytes = indexBlock.slice(i2 * LinkedArrayListSlot2.LENGTH, (i2 + 1) * LinkedArrayListSlot2.LENGTH);
|
|
2320
|
+
slotBlock[i2] = LinkedArrayListSlot2.fromBytes(slotBytes);
|
|
2321
|
+
}
|
|
2322
|
+
const keyAndIndex = Database3.keyAndIndexForLinkedArrayList(slotBlock, key, shift);
|
|
2323
|
+
if (keyAndIndex === null)
|
|
2324
|
+
throw new NoAvailableSlotsException;
|
|
2325
|
+
const nextKey = keyAndIndex.key;
|
|
2326
|
+
const i = keyAndIndex.index;
|
|
2327
|
+
const leafCount = Database3.blockLeafCount(slotBlock, shift, i);
|
|
2328
|
+
blocks.push(new LinkedArrayListBlockInfo(slotBlock, i, new LinkedArrayListSlot2(leafCount, new Slot(indexPos, 1 /* INDEX */))));
|
|
2329
|
+
if (shift === 0) {
|
|
2330
|
+
return;
|
|
2331
|
+
}
|
|
2332
|
+
const slot = slotBlock[i];
|
|
2333
|
+
switch (slot.slot.tag) {
|
|
2334
|
+
case 0 /* NONE */:
|
|
2335
|
+
throw new EmptySlotException;
|
|
2336
|
+
case 1 /* INDEX */:
|
|
2337
|
+
await this.readLinkedArrayListBlocks(slot.slot.value, nextKey, shift - 1, blocks);
|
|
2338
|
+
break;
|
|
2339
|
+
default:
|
|
2340
|
+
throw new UnexpectedTagException;
|
|
2341
|
+
}
|
|
2342
|
+
}
|
|
2343
|
+
populateArray(arr) {
|
|
2344
|
+
for (let i = 0;i < arr.length; i++) {
|
|
2345
|
+
arr[i] = new LinkedArrayListSlot2(0n, new Slot);
|
|
2346
|
+
}
|
|
2347
|
+
}
|
|
2348
|
+
async readLinkedArrayListSlice(header, offset, size) {
|
|
2349
|
+
const writer = this.core.writer();
|
|
2350
|
+
if (offset + size > header.size) {
|
|
2351
|
+
throw new KeyNotFoundException;
|
|
2352
|
+
}
|
|
2353
|
+
const leftBlocks = [];
|
|
2354
|
+
await this.readLinkedArrayListBlocks(header.ptr, offset, header.shift, leftBlocks);
|
|
2355
|
+
const rightBlocks = [];
|
|
2356
|
+
const rightKey = offset + size === 0n ? 0n : offset + size - 1n;
|
|
2357
|
+
await this.readLinkedArrayListBlocks(header.ptr, rightKey, header.shift, rightBlocks);
|
|
2358
|
+
const blockCount = leftBlocks.length;
|
|
2359
|
+
let nextSlots = [null, null];
|
|
2360
|
+
let nextShift = 0;
|
|
2361
|
+
for (let i = 0;i < blockCount; i++) {
|
|
2362
|
+
const isLeafNode = nextSlots[0] === null;
|
|
2363
|
+
const leftBlock = leftBlocks[blockCount - i - 1];
|
|
2364
|
+
const rightBlock = rightBlocks[blockCount - i - 1];
|
|
2365
|
+
const origBlockInfos = [leftBlock, rightBlock];
|
|
2366
|
+
let nextBlocks = [null, null];
|
|
2367
|
+
if (leftBlock.parentSlot.slot.value === rightBlock.parentSlot.slot.value) {
|
|
2368
|
+
let slotI = 0;
|
|
2369
|
+
const newRootBlock = new Array(SLOT_COUNT);
|
|
2370
|
+
this.populateArray(newRootBlock);
|
|
2371
|
+
if (size > 0n) {
|
|
2372
|
+
if (nextSlots[0] !== null) {
|
|
2373
|
+
newRootBlock[slotI] = nextSlots[0];
|
|
2374
|
+
} else {
|
|
2375
|
+
newRootBlock[slotI] = leftBlock.block[leftBlock.i];
|
|
2376
|
+
}
|
|
2377
|
+
slotI += 1;
|
|
2378
|
+
}
|
|
2379
|
+
if (size > 1n) {
|
|
2380
|
+
for (let j = leftBlock.i + 1;j < rightBlock.i; j++) {
|
|
2381
|
+
const middleSlot = leftBlock.block[j];
|
|
2382
|
+
newRootBlock[slotI] = middleSlot;
|
|
2383
|
+
slotI += 1;
|
|
2384
|
+
}
|
|
2385
|
+
if (nextSlots[1] !== null) {
|
|
2386
|
+
newRootBlock[slotI] = nextSlots[1];
|
|
2387
|
+
} else {
|
|
2388
|
+
newRootBlock[slotI] = leftBlock.block[rightBlock.i];
|
|
2389
|
+
}
|
|
2390
|
+
}
|
|
2391
|
+
nextBlocks[0] = newRootBlock;
|
|
2392
|
+
} else {
|
|
2393
|
+
let slotI = 0;
|
|
2394
|
+
const newLeftBlock = new Array(SLOT_COUNT);
|
|
2395
|
+
this.populateArray(newLeftBlock);
|
|
2396
|
+
if (nextSlots[0] !== null) {
|
|
2397
|
+
newLeftBlock[slotI] = nextSlots[0];
|
|
2398
|
+
} else {
|
|
2399
|
+
newLeftBlock[slotI] = leftBlock.block[leftBlock.i];
|
|
2400
|
+
}
|
|
2401
|
+
slotI += 1;
|
|
2402
|
+
for (let j = leftBlock.i + 1;j < leftBlock.block.length; j++) {
|
|
2403
|
+
const nextSlot = leftBlock.block[j];
|
|
2404
|
+
newLeftBlock[slotI] = nextSlot;
|
|
2405
|
+
slotI += 1;
|
|
2406
|
+
}
|
|
2407
|
+
nextBlocks[0] = newLeftBlock;
|
|
2408
|
+
slotI = 0;
|
|
2409
|
+
const newRightBlock = new Array(SLOT_COUNT);
|
|
2410
|
+
this.populateArray(newRightBlock);
|
|
2411
|
+
for (let j = 0;j < rightBlock.i; j++) {
|
|
2412
|
+
const firstSlot = rightBlock.block[j];
|
|
2413
|
+
newRightBlock[slotI] = firstSlot;
|
|
2414
|
+
slotI += 1;
|
|
2415
|
+
}
|
|
2416
|
+
if (nextSlots[1] !== null) {
|
|
2417
|
+
newRightBlock[slotI] = nextSlots[1];
|
|
2418
|
+
} else {
|
|
2419
|
+
newRightBlock[slotI] = rightBlock.block[rightBlock.i];
|
|
2420
|
+
}
|
|
2421
|
+
nextBlocks[1] = newRightBlock;
|
|
2422
|
+
nextShift += 1;
|
|
2423
|
+
}
|
|
2424
|
+
nextSlots = [null, null];
|
|
2425
|
+
await this.core.seek(await this.core.length());
|
|
2426
|
+
for (let j = 0;j < 2; j++) {
|
|
2427
|
+
const blockMaybe = nextBlocks[j];
|
|
2428
|
+
const origBlockInfo = origBlockInfos[j];
|
|
2429
|
+
if (blockMaybe !== null) {
|
|
2430
|
+
let eql = true;
|
|
2431
|
+
for (let k = 0;k < blockMaybe.length; k++) {
|
|
2432
|
+
const blockSlot = blockMaybe[k];
|
|
2433
|
+
const origSlot = origBlockInfo.block[k];
|
|
2434
|
+
if (!blockSlot.slot.equals(origSlot.slot)) {
|
|
2435
|
+
eql = false;
|
|
2436
|
+
break;
|
|
2437
|
+
}
|
|
2438
|
+
}
|
|
2439
|
+
if (eql) {
|
|
2440
|
+
nextSlots[j] = origBlockInfo.parentSlot;
|
|
2441
|
+
} else {
|
|
2442
|
+
const nextPtr = await this.core.position();
|
|
2443
|
+
let leafCount = 0n;
|
|
2444
|
+
for (let k = 0;k < blockMaybe.length; k++) {
|
|
2445
|
+
const blockSlot = blockMaybe[k];
|
|
2446
|
+
await writer.write(blockSlot.toBytes());
|
|
2447
|
+
if (isLeafNode) {
|
|
2448
|
+
if (!blockSlot.slot.empty()) {
|
|
2449
|
+
leafCount += 1n;
|
|
2450
|
+
}
|
|
2451
|
+
} else {
|
|
2452
|
+
leafCount += blockSlot.size;
|
|
2453
|
+
}
|
|
2454
|
+
}
|
|
2455
|
+
nextSlots[j] = new LinkedArrayListSlot2(leafCount, j === 0 ? new Slot(nextPtr, 1 /* INDEX */, true) : new Slot(nextPtr, 1 /* INDEX */));
|
|
2456
|
+
}
|
|
2457
|
+
}
|
|
2458
|
+
}
|
|
2459
|
+
if (nextSlots[0] !== null && nextSlots[1] === null) {
|
|
2460
|
+
break;
|
|
2461
|
+
}
|
|
2462
|
+
}
|
|
2463
|
+
const rootSlot = nextSlots[0];
|
|
2464
|
+
if (rootSlot === null)
|
|
2465
|
+
throw new ExpectedRootNodeException;
|
|
2466
|
+
return new LinkedArrayListHeader(nextShift, rootSlot.slot.value, size);
|
|
2467
|
+
}
|
|
2468
|
+
async readLinkedArrayListConcat(headerA, headerB) {
|
|
2469
|
+
const writer = this.core.writer();
|
|
2470
|
+
const blocksA = [];
|
|
2471
|
+
const keyA = headerA.size === 0n ? 0n : headerA.size - 1n;
|
|
2472
|
+
await this.readLinkedArrayListBlocks(headerA.ptr, keyA, headerA.shift, blocksA);
|
|
2473
|
+
const blocksB = [];
|
|
2474
|
+
await this.readLinkedArrayListBlocks(headerB.ptr, 0n, headerB.shift, blocksB);
|
|
2475
|
+
let nextSlots = [null, null];
|
|
2476
|
+
let nextShift = 0;
|
|
2477
|
+
for (let i = 0;i < Math.max(blocksA.length, blocksB.length); i++) {
|
|
2478
|
+
const blockInfos = [
|
|
2479
|
+
i < blocksA.length ? blocksA[blocksA.length - 1 - i] : null,
|
|
2480
|
+
i < blocksB.length ? blocksB[blocksB.length - 1 - i] : null
|
|
2481
|
+
];
|
|
2482
|
+
let nextBlocks = [null, null];
|
|
2483
|
+
const isLeafNode = nextSlots[0] === null;
|
|
2484
|
+
if (!isLeafNode) {
|
|
2485
|
+
nextShift += 1;
|
|
2486
|
+
}
|
|
2487
|
+
for (let j = 0;j < 2; j++) {
|
|
2488
|
+
const blockInfoMaybe = blockInfos[j];
|
|
2489
|
+
if (blockInfoMaybe !== null) {
|
|
2490
|
+
const block = new Array(SLOT_COUNT);
|
|
2491
|
+
this.populateArray(block);
|
|
2492
|
+
let targetI = 0;
|
|
2493
|
+
for (let sourceI = 0;sourceI < blockInfoMaybe.block.length; sourceI++) {
|
|
2494
|
+
const blockSlot = blockInfoMaybe.block[sourceI];
|
|
2495
|
+
if (!isLeafNode && blockInfoMaybe.i === sourceI) {
|
|
2496
|
+
continue;
|
|
2497
|
+
} else if (blockSlot.slot.empty()) {
|
|
2498
|
+
break;
|
|
2499
|
+
}
|
|
2500
|
+
block[targetI] = blockSlot;
|
|
2501
|
+
targetI += 1;
|
|
2502
|
+
}
|
|
2503
|
+
if (targetI === 0) {
|
|
2504
|
+
continue;
|
|
2505
|
+
}
|
|
2506
|
+
nextBlocks[j] = block;
|
|
2507
|
+
}
|
|
2508
|
+
}
|
|
2509
|
+
const slotsToWrite = new Array(SLOT_COUNT * 2);
|
|
2510
|
+
this.populateArray(slotsToWrite);
|
|
2511
|
+
let slotI = 0;
|
|
2512
|
+
if (nextBlocks[0] !== null) {
|
|
2513
|
+
for (const blockSlot of nextBlocks[0]) {
|
|
2514
|
+
if (blockSlot.slot.empty()) {
|
|
2515
|
+
break;
|
|
2516
|
+
}
|
|
2517
|
+
slotsToWrite[slotI] = blockSlot;
|
|
2518
|
+
slotI += 1;
|
|
2519
|
+
}
|
|
2520
|
+
}
|
|
2521
|
+
for (const slotMaybe of nextSlots) {
|
|
2522
|
+
if (slotMaybe !== null) {
|
|
2523
|
+
slotsToWrite[slotI] = slotMaybe;
|
|
2524
|
+
slotI += 1;
|
|
2525
|
+
}
|
|
2526
|
+
}
|
|
2527
|
+
if (nextBlocks[1] !== null) {
|
|
2528
|
+
for (const blockSlot of nextBlocks[1]) {
|
|
2529
|
+
if (blockSlot.slot.empty()) {
|
|
2530
|
+
break;
|
|
2531
|
+
}
|
|
2532
|
+
slotsToWrite[slotI] = blockSlot;
|
|
2533
|
+
slotI += 1;
|
|
2534
|
+
}
|
|
2535
|
+
}
|
|
2536
|
+
nextSlots = [null, null];
|
|
2537
|
+
const blocks = [new Array(SLOT_COUNT), new Array(SLOT_COUNT)];
|
|
2538
|
+
this.populateArray(blocks[0]);
|
|
2539
|
+
this.populateArray(blocks[1]);
|
|
2540
|
+
if (slotI > SLOT_COUNT) {
|
|
2541
|
+
if (headerA.size < headerB.size) {
|
|
2542
|
+
for (let j = 0;j < slotI - SLOT_COUNT; j++) {
|
|
2543
|
+
blocks[0][j] = slotsToWrite[j];
|
|
2544
|
+
}
|
|
2545
|
+
for (let j = 0;j < SLOT_COUNT; j++) {
|
|
2546
|
+
blocks[1][j] = slotsToWrite[j + (slotI - SLOT_COUNT)];
|
|
2547
|
+
}
|
|
2548
|
+
} else {
|
|
2549
|
+
for (let j = 0;j < SLOT_COUNT; j++) {
|
|
2550
|
+
blocks[0][j] = slotsToWrite[j];
|
|
2551
|
+
}
|
|
2552
|
+
for (let j = 0;j < slotI - SLOT_COUNT; j++) {
|
|
2553
|
+
blocks[1][j] = slotsToWrite[j + SLOT_COUNT];
|
|
2554
|
+
}
|
|
2555
|
+
}
|
|
2556
|
+
} else {
|
|
2557
|
+
for (let j = 0;j < slotI; j++) {
|
|
2558
|
+
blocks[0][j] = slotsToWrite[j];
|
|
2559
|
+
}
|
|
2560
|
+
}
|
|
2561
|
+
await this.core.seek(await this.core.length());
|
|
2562
|
+
for (let blockI = 0;blockI < blocks.length; blockI++) {
|
|
2563
|
+
const block = blocks[blockI];
|
|
2564
|
+
if (block[0].slot.empty()) {
|
|
2565
|
+
break;
|
|
2566
|
+
}
|
|
2567
|
+
const nextPtr = await this.core.position();
|
|
2568
|
+
let leafCount = 0n;
|
|
2569
|
+
for (const blockSlot of block) {
|
|
2570
|
+
await writer.write(blockSlot.toBytes());
|
|
2571
|
+
if (isLeafNode) {
|
|
2572
|
+
if (!blockSlot.slot.empty()) {
|
|
2573
|
+
leafCount += 1n;
|
|
2574
|
+
}
|
|
2575
|
+
} else {
|
|
2576
|
+
leafCount += blockSlot.size;
|
|
2577
|
+
}
|
|
2578
|
+
}
|
|
2579
|
+
nextSlots[blockI] = new LinkedArrayListSlot2(leafCount, new Slot(nextPtr, 1 /* INDEX */, true));
|
|
2580
|
+
}
|
|
2581
|
+
}
|
|
2582
|
+
let rootPtr;
|
|
2583
|
+
if (nextSlots[0] !== null) {
|
|
2584
|
+
if (nextSlots[1] !== null) {
|
|
2585
|
+
const block = new Array(SLOT_COUNT);
|
|
2586
|
+
this.populateArray(block);
|
|
2587
|
+
block[0] = nextSlots[0];
|
|
2588
|
+
block[1] = nextSlots[1];
|
|
2589
|
+
const newPtr = await this.core.length();
|
|
2590
|
+
for (const blockSlot of block) {
|
|
2591
|
+
await writer.write(blockSlot.toBytes());
|
|
2592
|
+
}
|
|
2593
|
+
if (nextShift === MAX_BRANCH_LENGTH)
|
|
2594
|
+
throw new MaxShiftExceededException;
|
|
2595
|
+
nextShift += 1;
|
|
2596
|
+
rootPtr = newPtr;
|
|
2597
|
+
} else {
|
|
2598
|
+
rootPtr = nextSlots[0].slot.value;
|
|
2599
|
+
}
|
|
2600
|
+
} else {
|
|
2601
|
+
rootPtr = headerA.ptr;
|
|
2602
|
+
}
|
|
2603
|
+
return new LinkedArrayListHeader(nextShift, rootPtr, headerA.size + headerB.size);
|
|
2604
|
+
}
|
|
2605
|
+
}
|
|
2606
|
+
var VERSION = 0, MAGIC_NUMBER, BIT_COUNT = 4, SLOT_COUNT, MASK, INDEX_BLOCK_SIZE, LINKED_ARRAY_LIST_SLOT_LENGTH, LINKED_ARRAY_LIST_INDEX_BLOCK_SIZE, MAX_BRANCH_LENGTH = 16, WriteMode, TopLevelArrayListHeader, LinkedArrayListSlot2;
|
|
2607
|
+
var init_database = __esm(() => {
|
|
2608
|
+
init_tag();
|
|
2609
|
+
init_slot();
|
|
2610
|
+
init_exceptions();
|
|
2611
|
+
init_writeable_data();
|
|
2612
|
+
MAGIC_NUMBER = new Uint8Array([120, 105, 116]);
|
|
2613
|
+
SLOT_COUNT = 1 << BIT_COUNT;
|
|
2614
|
+
MASK = BigInt(SLOT_COUNT - 1);
|
|
2615
|
+
INDEX_BLOCK_SIZE = Slot.LENGTH * SLOT_COUNT;
|
|
2616
|
+
LINKED_ARRAY_LIST_SLOT_LENGTH = 8 + Slot.LENGTH;
|
|
2617
|
+
LINKED_ARRAY_LIST_INDEX_BLOCK_SIZE = LINKED_ARRAY_LIST_SLOT_LENGTH * SLOT_COUNT;
|
|
2618
|
+
((WriteMode2) => {
|
|
2619
|
+
WriteMode2[WriteMode2["READ_ONLY"] = 0] = "READ_ONLY";
|
|
2620
|
+
WriteMode2[WriteMode2["READ_WRITE"] = 1] = "READ_WRITE";
|
|
2621
|
+
})(WriteMode ||= {});
|
|
2622
|
+
TopLevelArrayListHeader = class TopLevelArrayListHeader {
|
|
2623
|
+
fileSize;
|
|
2624
|
+
parent;
|
|
2625
|
+
static LENGTH = 8 + ArrayListHeader.LENGTH;
|
|
2626
|
+
constructor(fileSize, parent) {
|
|
2627
|
+
this.fileSize = fileSize;
|
|
2628
|
+
this.parent = parent;
|
|
2629
|
+
}
|
|
2630
|
+
toBytes() {
|
|
2631
|
+
const buffer = new ArrayBuffer(TopLevelArrayListHeader.LENGTH);
|
|
2632
|
+
const view = new DataView(buffer);
|
|
2633
|
+
const arr = new Uint8Array(buffer);
|
|
2634
|
+
arr.set(this.parent.toBytes(), 0);
|
|
2635
|
+
view.setBigInt64(ArrayListHeader.LENGTH, this.fileSize, false);
|
|
2636
|
+
return arr;
|
|
2637
|
+
}
|
|
2638
|
+
};
|
|
2639
|
+
LinkedArrayListSlot2 = class LinkedArrayListSlot2 {
|
|
2640
|
+
size;
|
|
2641
|
+
slot;
|
|
2642
|
+
static LENGTH = 8 + Slot.LENGTH;
|
|
2643
|
+
constructor(size, slot) {
|
|
2644
|
+
this.size = size;
|
|
2645
|
+
this.slot = slot;
|
|
2646
|
+
}
|
|
2647
|
+
withSize(size) {
|
|
2648
|
+
return new LinkedArrayListSlot2(size, this.slot);
|
|
2649
|
+
}
|
|
2650
|
+
toBytes() {
|
|
2651
|
+
const buffer = new ArrayBuffer(LinkedArrayListSlot2.LENGTH);
|
|
2652
|
+
const view = new DataView(buffer);
|
|
2653
|
+
const arr = new Uint8Array(buffer);
|
|
2654
|
+
arr.set(this.slot.toBytes(), 0);
|
|
2655
|
+
view.setBigInt64(Slot.LENGTH, this.size, false);
|
|
2656
|
+
return arr;
|
|
2657
|
+
}
|
|
2658
|
+
static fromBytes(bytes) {
|
|
2659
|
+
const slotBytes = bytes.slice(0, Slot.LENGTH);
|
|
2660
|
+
const slot = Slot.fromBytes(slotBytes);
|
|
2661
|
+
const view = new DataView(bytes.buffer, bytes.byteOffset, bytes.byteLength);
|
|
2662
|
+
const size = checkLong(view.getBigInt64(Slot.LENGTH, false));
|
|
2663
|
+
return new LinkedArrayListSlot2(size, slot);
|
|
2664
|
+
}
|
|
2665
|
+
};
|
|
2666
|
+
});
|
|
2667
|
+
|
|
2668
|
+
// src/index.ts
|
|
2669
|
+
init_tag();
|
|
2670
|
+
init_slot();
|
|
2671
|
+
init_writeable_data();
|
|
2672
|
+
init_exceptions();
|
|
2673
|
+
|
|
2674
|
+
// src/random-access-memory.ts
|
|
2675
|
+
class RandomAccessMemory {
|
|
2676
|
+
buffer;
|
|
2677
|
+
_position = 0;
|
|
2678
|
+
_count = 0;
|
|
2679
|
+
constructor(initialSize = 1024) {
|
|
2680
|
+
this.buffer = new Uint8Array(initialSize);
|
|
2681
|
+
}
|
|
2682
|
+
ensureCapacity(minCapacity) {
|
|
2683
|
+
if (minCapacity > this.buffer.length) {
|
|
2684
|
+
let newCapacity = this.buffer.length * 2;
|
|
2685
|
+
if (newCapacity < minCapacity) {
|
|
2686
|
+
newCapacity = minCapacity;
|
|
2687
|
+
}
|
|
2688
|
+
const newBuffer = new Uint8Array(newCapacity);
|
|
2689
|
+
newBuffer.set(this.buffer.subarray(0, this._count));
|
|
2690
|
+
this.buffer = newBuffer;
|
|
2691
|
+
}
|
|
2692
|
+
}
|
|
2693
|
+
size() {
|
|
2694
|
+
return this._count;
|
|
2695
|
+
}
|
|
2696
|
+
seek(pos) {
|
|
2697
|
+
if (pos > this._count) {
|
|
2698
|
+
this._position = this._count;
|
|
2699
|
+
} else {
|
|
2700
|
+
this._position = pos;
|
|
2701
|
+
}
|
|
2702
|
+
}
|
|
2703
|
+
getPosition() {
|
|
2704
|
+
return this._position;
|
|
2705
|
+
}
|
|
2706
|
+
setLength(len) {
|
|
2707
|
+
if (len === 0) {
|
|
2708
|
+
this.reset();
|
|
2709
|
+
} else {
|
|
2710
|
+
if (len > this._count)
|
|
2711
|
+
throw new Error("Cannot extend length");
|
|
2712
|
+
this._count = len;
|
|
2713
|
+
if (this._position > len) {
|
|
2714
|
+
this._position = len;
|
|
2715
|
+
}
|
|
2716
|
+
}
|
|
2717
|
+
}
|
|
2718
|
+
reset() {
|
|
2719
|
+
this._count = 0;
|
|
2720
|
+
this._position = 0;
|
|
2721
|
+
}
|
|
2722
|
+
toByteArray() {
|
|
2723
|
+
return this.buffer.slice(0, this._count);
|
|
2724
|
+
}
|
|
2725
|
+
async write(data) {
|
|
2726
|
+
const pos = this._position;
|
|
2727
|
+
if (pos < this._count) {
|
|
2728
|
+
const bytesBeforeEnd = Math.min(data.length, this._count - pos);
|
|
2729
|
+
for (let i = 0;i < bytesBeforeEnd; i++) {
|
|
2730
|
+
this.buffer[pos + i] = data[i];
|
|
2731
|
+
}
|
|
2732
|
+
if (bytesBeforeEnd < data.length) {
|
|
2733
|
+
const bytesAfterEnd = data.length - bytesBeforeEnd;
|
|
2734
|
+
this.ensureCapacity(this._count + bytesAfterEnd);
|
|
2735
|
+
this.buffer.set(data.subarray(bytesBeforeEnd), this._count);
|
|
2736
|
+
this._count += bytesAfterEnd;
|
|
2737
|
+
}
|
|
2738
|
+
} else {
|
|
2739
|
+
this.ensureCapacity(this._count + data.length);
|
|
2740
|
+
this.buffer.set(data, this._count);
|
|
2741
|
+
this._count += data.length;
|
|
2742
|
+
}
|
|
2743
|
+
this._position = pos + data.length;
|
|
2744
|
+
}
|
|
2745
|
+
async writeByte(v) {
|
|
2746
|
+
await this.write(new Uint8Array([v & 255]));
|
|
2747
|
+
}
|
|
2748
|
+
async writeShort(v) {
|
|
2749
|
+
const buffer = new ArrayBuffer(2);
|
|
2750
|
+
const view = new DataView(buffer);
|
|
2751
|
+
view.setInt16(0, v, false);
|
|
2752
|
+
await this.write(new Uint8Array(buffer));
|
|
2753
|
+
}
|
|
2754
|
+
async writeLong(v) {
|
|
2755
|
+
const buffer = new ArrayBuffer(8);
|
|
2756
|
+
const view = new DataView(buffer);
|
|
2757
|
+
view.setBigInt64(0, v, false);
|
|
2758
|
+
await this.write(new Uint8Array(buffer));
|
|
2759
|
+
}
|
|
2760
|
+
async readFully(b) {
|
|
2761
|
+
const pos = this._position;
|
|
2762
|
+
if (pos + b.length > this._count) {
|
|
2763
|
+
throw new Error("End of stream");
|
|
2764
|
+
}
|
|
2765
|
+
b.set(this.buffer.subarray(pos, pos + b.length));
|
|
2766
|
+
this._position = pos + b.length;
|
|
2767
|
+
}
|
|
2768
|
+
async readByte() {
|
|
2769
|
+
const bytes = new Uint8Array(1);
|
|
2770
|
+
await this.readFully(bytes);
|
|
2771
|
+
return bytes[0];
|
|
2772
|
+
}
|
|
2773
|
+
async readShort() {
|
|
2774
|
+
const bytes = new Uint8Array(2);
|
|
2775
|
+
await this.readFully(bytes);
|
|
2776
|
+
const view = new DataView(bytes.buffer, bytes.byteOffset, bytes.byteLength);
|
|
2777
|
+
return view.getInt16(0, false);
|
|
2778
|
+
}
|
|
2779
|
+
async readInt() {
|
|
2780
|
+
const bytes = new Uint8Array(4);
|
|
2781
|
+
await this.readFully(bytes);
|
|
2782
|
+
const view = new DataView(bytes.buffer, bytes.byteOffset, bytes.byteLength);
|
|
2783
|
+
return view.getInt32(0, false);
|
|
2784
|
+
}
|
|
2785
|
+
async readLong() {
|
|
2786
|
+
const bytes = new Uint8Array(8);
|
|
2787
|
+
await this.readFully(bytes);
|
|
2788
|
+
const view = new DataView(bytes.buffer, bytes.byteOffset, bytes.byteLength);
|
|
2789
|
+
return view.getBigInt64(0, false);
|
|
2790
|
+
}
|
|
2791
|
+
}
|
|
2792
|
+
// src/core-memory.ts
|
|
2793
|
+
class CoreMemory {
|
|
2794
|
+
memory;
|
|
2795
|
+
constructor(memory) {
|
|
2796
|
+
this.memory = memory;
|
|
2797
|
+
}
|
|
2798
|
+
reader() {
|
|
2799
|
+
return this.memory;
|
|
2800
|
+
}
|
|
2801
|
+
writer() {
|
|
2802
|
+
return this.memory;
|
|
2803
|
+
}
|
|
2804
|
+
async length() {
|
|
2805
|
+
return BigInt(this.memory.size());
|
|
2806
|
+
}
|
|
2807
|
+
async seek(pos) {
|
|
2808
|
+
this.memory.seek(Number(pos));
|
|
2809
|
+
}
|
|
2810
|
+
async position() {
|
|
2811
|
+
return BigInt(this.memory.getPosition());
|
|
2812
|
+
}
|
|
2813
|
+
async setLength(len) {
|
|
2814
|
+
this.memory.setLength(Number(len));
|
|
2815
|
+
}
|
|
2816
|
+
async flush() {}
|
|
2817
|
+
async sync() {}
|
|
2818
|
+
}
|
|
2819
|
+
// src/core-file.ts
|
|
2820
|
+
class FileDataReader {
|
|
2821
|
+
file;
|
|
2822
|
+
position;
|
|
2823
|
+
buffer = null;
|
|
2824
|
+
bufferStart = 0;
|
|
2825
|
+
bufferEnd = 0;
|
|
2826
|
+
constructor(file, position) {
|
|
2827
|
+
this.file = file;
|
|
2828
|
+
this.position = position;
|
|
2829
|
+
}
|
|
2830
|
+
setPosition(pos) {
|
|
2831
|
+
this.position = pos;
|
|
2832
|
+
}
|
|
2833
|
+
getPosition() {
|
|
2834
|
+
return this.position;
|
|
2835
|
+
}
|
|
2836
|
+
async readFully(b) {
|
|
2837
|
+
const slice = this.file.slice(this.position, this.position + b.length);
|
|
2838
|
+
const data = await slice.arrayBuffer();
|
|
2839
|
+
b.set(new Uint8Array(data));
|
|
2840
|
+
this.position += b.length;
|
|
2841
|
+
}
|
|
2842
|
+
async readByte() {
|
|
2843
|
+
const bytes = new Uint8Array(1);
|
|
2844
|
+
await this.readFully(bytes);
|
|
2845
|
+
return bytes[0];
|
|
2846
|
+
}
|
|
2847
|
+
async readShort() {
|
|
2848
|
+
const bytes = new Uint8Array(2);
|
|
2849
|
+
await this.readFully(bytes);
|
|
2850
|
+
const view = new DataView(bytes.buffer, bytes.byteOffset, bytes.byteLength);
|
|
2851
|
+
return view.getInt16(0, false);
|
|
2852
|
+
}
|
|
2853
|
+
async readInt() {
|
|
2854
|
+
const bytes = new Uint8Array(4);
|
|
2855
|
+
await this.readFully(bytes);
|
|
2856
|
+
const view = new DataView(bytes.buffer, bytes.byteOffset, bytes.byteLength);
|
|
2857
|
+
return view.getInt32(0, false);
|
|
2858
|
+
}
|
|
2859
|
+
async readLong() {
|
|
2860
|
+
const bytes = new Uint8Array(8);
|
|
2861
|
+
await this.readFully(bytes);
|
|
2862
|
+
const view = new DataView(bytes.buffer, bytes.byteOffset, bytes.byteLength);
|
|
2863
|
+
return view.getBigInt64(0, false);
|
|
2864
|
+
}
|
|
2865
|
+
}
|
|
2866
|
+
|
|
2867
|
+
class FileDataWriter {
|
|
2868
|
+
filePath;
|
|
2869
|
+
position;
|
|
2870
|
+
pendingWrites = [];
|
|
2871
|
+
constructor(filePath, position) {
|
|
2872
|
+
this.filePath = filePath;
|
|
2873
|
+
this.position = position;
|
|
2874
|
+
}
|
|
2875
|
+
setPosition(pos) {
|
|
2876
|
+
this.position = pos;
|
|
2877
|
+
}
|
|
2878
|
+
getPosition() {
|
|
2879
|
+
return this.position;
|
|
2880
|
+
}
|
|
2881
|
+
async write(buffer) {
|
|
2882
|
+
const file = Bun.file(this.filePath);
|
|
2883
|
+
const currentSize = file.size;
|
|
2884
|
+
if (this.position >= currentSize) {
|
|
2885
|
+
const existingData = currentSize > 0 ? new Uint8Array(await file.arrayBuffer()) : new Uint8Array(0);
|
|
2886
|
+
const newData = new Uint8Array(this.position + buffer.length);
|
|
2887
|
+
newData.set(existingData);
|
|
2888
|
+
newData.set(buffer, this.position);
|
|
2889
|
+
await Bun.write(this.filePath, newData);
|
|
2890
|
+
} else {
|
|
2891
|
+
const existingData = new Uint8Array(await file.arrayBuffer());
|
|
2892
|
+
const newSize = Math.max(existingData.length, this.position + buffer.length);
|
|
2893
|
+
const newData = new Uint8Array(newSize);
|
|
2894
|
+
newData.set(existingData);
|
|
2895
|
+
newData.set(buffer, this.position);
|
|
2896
|
+
await Bun.write(this.filePath, newData);
|
|
2897
|
+
}
|
|
2898
|
+
this.position += buffer.length;
|
|
2899
|
+
}
|
|
2900
|
+
async writeByte(v) {
|
|
2901
|
+
await this.write(new Uint8Array([v & 255]));
|
|
2902
|
+
}
|
|
2903
|
+
async writeShort(v) {
|
|
2904
|
+
const buffer = new ArrayBuffer(2);
|
|
2905
|
+
const view = new DataView(buffer);
|
|
2906
|
+
view.setInt16(0, v, false);
|
|
2907
|
+
await this.write(new Uint8Array(buffer));
|
|
2908
|
+
}
|
|
2909
|
+
async writeLong(v) {
|
|
2910
|
+
const buffer = new ArrayBuffer(8);
|
|
2911
|
+
const view = new DataView(buffer);
|
|
2912
|
+
view.setBigInt64(0, v, false);
|
|
2913
|
+
await this.write(new Uint8Array(buffer));
|
|
2914
|
+
}
|
|
2915
|
+
}
|
|
2916
|
+
|
|
2917
|
+
class CoreFile {
|
|
2918
|
+
filePath;
|
|
2919
|
+
_position = 0;
|
|
2920
|
+
_reader;
|
|
2921
|
+
_writer;
|
|
2922
|
+
constructor(filePath) {
|
|
2923
|
+
this.filePath = filePath;
|
|
2924
|
+
this._reader = new FileDataReader(Bun.file(filePath), 0);
|
|
2925
|
+
this._writer = new FileDataWriter(filePath, 0);
|
|
2926
|
+
}
|
|
2927
|
+
static async create(filePath) {
|
|
2928
|
+
const file = Bun.file(filePath);
|
|
2929
|
+
if (!await file.exists()) {
|
|
2930
|
+
await Bun.write(filePath, new Uint8Array(0));
|
|
2931
|
+
}
|
|
2932
|
+
return new CoreFile(filePath);
|
|
2933
|
+
}
|
|
2934
|
+
reader() {
|
|
2935
|
+
return this._reader;
|
|
2936
|
+
}
|
|
2937
|
+
writer() {
|
|
2938
|
+
return this._writer;
|
|
2939
|
+
}
|
|
2940
|
+
async length() {
|
|
2941
|
+
const file = Bun.file(this.filePath);
|
|
2942
|
+
return BigInt(file.size);
|
|
2943
|
+
}
|
|
2944
|
+
async seek(pos) {
|
|
2945
|
+
this._position = Number(pos);
|
|
2946
|
+
this._reader.setPosition(this._position);
|
|
2947
|
+
this._writer.setPosition(this._position);
|
|
2948
|
+
}
|
|
2949
|
+
async position() {
|
|
2950
|
+
return BigInt(this._reader.getPosition());
|
|
2951
|
+
}
|
|
2952
|
+
async setLength(len) {
|
|
2953
|
+
const file = Bun.file(this.filePath);
|
|
2954
|
+
const currentData = new Uint8Array(await file.arrayBuffer());
|
|
2955
|
+
const newData = currentData.slice(0, Number(len));
|
|
2956
|
+
await Bun.write(this.filePath, newData);
|
|
2957
|
+
}
|
|
2958
|
+
async flush() {}
|
|
2959
|
+
async sync() {}
|
|
2960
|
+
}
|
|
2961
|
+
// src/hasher.ts
|
|
2962
|
+
class Hasher {
|
|
2963
|
+
algorithm;
|
|
2964
|
+
id;
|
|
2965
|
+
digestLength;
|
|
2966
|
+
constructor(algorithm, id = 0) {
|
|
2967
|
+
this.algorithm = algorithm;
|
|
2968
|
+
this.id = id;
|
|
2969
|
+
switch (algorithm) {
|
|
2970
|
+
case "SHA-1":
|
|
2971
|
+
this.digestLength = 20;
|
|
2972
|
+
break;
|
|
2973
|
+
case "SHA-256":
|
|
2974
|
+
this.digestLength = 32;
|
|
2975
|
+
break;
|
|
2976
|
+
case "SHA-384":
|
|
2977
|
+
this.digestLength = 48;
|
|
2978
|
+
break;
|
|
2979
|
+
case "SHA-512":
|
|
2980
|
+
this.digestLength = 64;
|
|
2981
|
+
break;
|
|
2982
|
+
default:
|
|
2983
|
+
throw new Error(`Unsupported hash algorithm: ${algorithm}`);
|
|
2984
|
+
}
|
|
2985
|
+
}
|
|
2986
|
+
async digest(data) {
|
|
2987
|
+
const buffer = new ArrayBuffer(data.length);
|
|
2988
|
+
const view = new Uint8Array(buffer);
|
|
2989
|
+
view.set(data);
|
|
2990
|
+
const hashBuffer = await crypto.subtle.digest(this.algorithm, buffer);
|
|
2991
|
+
return new Uint8Array(hashBuffer);
|
|
2992
|
+
}
|
|
2993
|
+
static stringToId(hashIdName) {
|
|
2994
|
+
const bytes = new TextEncoder().encode(hashIdName);
|
|
2995
|
+
if (bytes.length !== 4) {
|
|
2996
|
+
throw new Error("Name must be exactly four bytes long");
|
|
2997
|
+
}
|
|
2998
|
+
const view = new DataView(bytes.buffer, bytes.byteOffset, bytes.byteLength);
|
|
2999
|
+
return view.getInt32(0, false);
|
|
3000
|
+
}
|
|
3001
|
+
static idToString(id) {
|
|
3002
|
+
const buffer = new ArrayBuffer(4);
|
|
3003
|
+
const view = new DataView(buffer);
|
|
3004
|
+
view.setInt32(0, id, false);
|
|
3005
|
+
return new TextDecoder().decode(new Uint8Array(buffer));
|
|
3006
|
+
}
|
|
3007
|
+
}
|
|
3008
|
+
|
|
3009
|
+
// src/index.ts
|
|
3010
|
+
init_database();
|
|
3011
|
+
init_read_cursor();
|
|
3012
|
+
init_write_cursor();
|
|
3013
|
+
|
|
3014
|
+
// src/read-array-list.ts
|
|
3015
|
+
init_tag();
|
|
3016
|
+
init_database();
|
|
3017
|
+
init_exceptions();
|
|
3018
|
+
|
|
3019
|
+
class ReadArrayList {
|
|
3020
|
+
cursor;
|
|
3021
|
+
constructor(cursor) {
|
|
3022
|
+
switch (cursor.slotPtr.slot.tag) {
|
|
3023
|
+
case 0 /* NONE */:
|
|
3024
|
+
case 2 /* ARRAY_LIST */:
|
|
3025
|
+
this.cursor = cursor;
|
|
3026
|
+
break;
|
|
3027
|
+
default:
|
|
3028
|
+
throw new UnexpectedTagException;
|
|
3029
|
+
}
|
|
3030
|
+
}
|
|
3031
|
+
slot() {
|
|
3032
|
+
return this.cursor.slot();
|
|
3033
|
+
}
|
|
3034
|
+
async count() {
|
|
3035
|
+
return this.cursor.count();
|
|
3036
|
+
}
|
|
3037
|
+
iterator() {
|
|
3038
|
+
return this.cursor.iterator();
|
|
3039
|
+
}
|
|
3040
|
+
async* [Symbol.asyncIterator]() {
|
|
3041
|
+
yield* this.cursor;
|
|
3042
|
+
}
|
|
3043
|
+
async getCursor(index) {
|
|
3044
|
+
return this.cursor.readPath([new ArrayListGet2(index)]);
|
|
3045
|
+
}
|
|
3046
|
+
async getSlot(index) {
|
|
3047
|
+
return this.cursor.readPathSlot([new ArrayListGet2(index)]);
|
|
3048
|
+
}
|
|
3049
|
+
}
|
|
3050
|
+
// src/write-array-list.ts
|
|
3051
|
+
init_database();
|
|
3052
|
+
|
|
3053
|
+
class WriteArrayList extends ReadArrayList {
|
|
3054
|
+
constructor(cursor) {
|
|
3055
|
+
super(cursor);
|
|
3056
|
+
}
|
|
3057
|
+
static async create(cursor) {
|
|
3058
|
+
const newCursor = await cursor.writePath([new ArrayListInit]);
|
|
3059
|
+
return new WriteArrayList(newCursor);
|
|
3060
|
+
}
|
|
3061
|
+
iterator() {
|
|
3062
|
+
return this.cursor.iterator();
|
|
3063
|
+
}
|
|
3064
|
+
async* [Symbol.asyncIterator]() {
|
|
3065
|
+
yield* this.cursor;
|
|
3066
|
+
}
|
|
3067
|
+
async put(index, data) {
|
|
3068
|
+
await this.cursor.writePath([
|
|
3069
|
+
new ArrayListGet2(index),
|
|
3070
|
+
new WriteData(data)
|
|
3071
|
+
]);
|
|
3072
|
+
}
|
|
3073
|
+
async putCursor(index) {
|
|
3074
|
+
return this.cursor.writePath([new ArrayListGet2(index)]);
|
|
3075
|
+
}
|
|
3076
|
+
async append(data) {
|
|
3077
|
+
await this.cursor.writePath([
|
|
3078
|
+
new ArrayListAppend,
|
|
3079
|
+
new WriteData(data)
|
|
3080
|
+
]);
|
|
3081
|
+
}
|
|
3082
|
+
async appendCursor() {
|
|
3083
|
+
return this.cursor.writePath([new ArrayListAppend]);
|
|
3084
|
+
}
|
|
3085
|
+
async appendContext(data, fn) {
|
|
3086
|
+
await this.cursor.writePath([
|
|
3087
|
+
new ArrayListAppend,
|
|
3088
|
+
new WriteData(data),
|
|
3089
|
+
new Context(fn)
|
|
3090
|
+
]);
|
|
3091
|
+
}
|
|
3092
|
+
async slice(size) {
|
|
3093
|
+
await this.cursor.writePath([new ArrayListSlice(size)]);
|
|
3094
|
+
}
|
|
3095
|
+
}
|
|
3096
|
+
// src/read-hash-map.ts
|
|
3097
|
+
init_tag();
|
|
3098
|
+
init_database();
|
|
3099
|
+
init_exceptions();
|
|
3100
|
+
|
|
3101
|
+
class ReadHashMap {
|
|
3102
|
+
cursor;
|
|
3103
|
+
constructor() {}
|
|
3104
|
+
static async create(cursor) {
|
|
3105
|
+
const map = new ReadHashMap;
|
|
3106
|
+
switch (cursor.slotPtr.slot.tag) {
|
|
3107
|
+
case 0 /* NONE */:
|
|
3108
|
+
case 4 /* HASH_MAP */:
|
|
3109
|
+
case 11 /* HASH_SET */:
|
|
3110
|
+
map.cursor = cursor;
|
|
3111
|
+
break;
|
|
3112
|
+
default:
|
|
3113
|
+
throw new UnexpectedTagException;
|
|
3114
|
+
}
|
|
3115
|
+
return map;
|
|
3116
|
+
}
|
|
3117
|
+
slot() {
|
|
3118
|
+
return this.cursor.slot();
|
|
3119
|
+
}
|
|
3120
|
+
iterator() {
|
|
3121
|
+
return this.cursor.iterator();
|
|
3122
|
+
}
|
|
3123
|
+
async* [Symbol.asyncIterator]() {
|
|
3124
|
+
yield* this.cursor;
|
|
3125
|
+
}
|
|
3126
|
+
async getCursorByString(key) {
|
|
3127
|
+
const hash = await this.cursor.db.hasher.digest(new TextEncoder().encode(key));
|
|
3128
|
+
return this.getCursor(hash);
|
|
3129
|
+
}
|
|
3130
|
+
async getSlotByString(key) {
|
|
3131
|
+
const hash = await this.cursor.db.hasher.digest(new TextEncoder().encode(key));
|
|
3132
|
+
return this.getSlot(hash);
|
|
3133
|
+
}
|
|
3134
|
+
async getKeyCursorByString(key) {
|
|
3135
|
+
const hash = await this.cursor.db.hasher.digest(new TextEncoder().encode(key));
|
|
3136
|
+
return this.getKeyCursor(hash);
|
|
3137
|
+
}
|
|
3138
|
+
async getKeySlotByString(key) {
|
|
3139
|
+
const hash = await this.cursor.db.hasher.digest(new TextEncoder().encode(key));
|
|
3140
|
+
return this.getKeySlot(hash);
|
|
3141
|
+
}
|
|
3142
|
+
async getKeyValuePairByString(key) {
|
|
3143
|
+
const hash = await this.cursor.db.hasher.digest(new TextEncoder().encode(key));
|
|
3144
|
+
return this.getKeyValuePair(hash);
|
|
3145
|
+
}
|
|
3146
|
+
async getCursorByBytes(key) {
|
|
3147
|
+
const hash = await this.cursor.db.hasher.digest(key.value);
|
|
3148
|
+
return this.getCursor(hash);
|
|
3149
|
+
}
|
|
3150
|
+
async getSlotByBytes(key) {
|
|
3151
|
+
const hash = await this.cursor.db.hasher.digest(key.value);
|
|
3152
|
+
return this.getSlot(hash);
|
|
3153
|
+
}
|
|
3154
|
+
async getKeyCursorByBytes(key) {
|
|
3155
|
+
const hash = await this.cursor.db.hasher.digest(key.value);
|
|
3156
|
+
return this.getKeyCursor(hash);
|
|
3157
|
+
}
|
|
3158
|
+
async getKeySlotByBytes(key) {
|
|
3159
|
+
const hash = await this.cursor.db.hasher.digest(key.value);
|
|
3160
|
+
return this.getKeySlot(hash);
|
|
3161
|
+
}
|
|
3162
|
+
async getKeyValuePairByBytes(key) {
|
|
3163
|
+
const hash = await this.cursor.db.hasher.digest(key.value);
|
|
3164
|
+
return this.getKeyValuePair(hash);
|
|
3165
|
+
}
|
|
3166
|
+
async getCursor(hash) {
|
|
3167
|
+
return this.cursor.readPath([new HashMapGet(new HashMapGetValue(hash))]);
|
|
3168
|
+
}
|
|
3169
|
+
async getSlot(hash) {
|
|
3170
|
+
return this.cursor.readPathSlot([new HashMapGet(new HashMapGetValue(hash))]);
|
|
3171
|
+
}
|
|
3172
|
+
async getKeyCursor(hash) {
|
|
3173
|
+
return this.cursor.readPath([new HashMapGet(new HashMapGetKey(hash))]);
|
|
3174
|
+
}
|
|
3175
|
+
async getKeySlot(hash) {
|
|
3176
|
+
return this.cursor.readPathSlot([new HashMapGet(new HashMapGetKey(hash))]);
|
|
3177
|
+
}
|
|
3178
|
+
async getKeyValuePair(hash) {
|
|
3179
|
+
const cursor = await this.cursor.readPath([new HashMapGet(new HashMapGetKVPair(hash))]);
|
|
3180
|
+
if (cursor === null) {
|
|
3181
|
+
return null;
|
|
3182
|
+
} else {
|
|
3183
|
+
return cursor.readKeyValuePair();
|
|
3184
|
+
}
|
|
3185
|
+
}
|
|
3186
|
+
}
|
|
3187
|
+
// src/write-hash-map.ts
|
|
3188
|
+
init_database();
|
|
3189
|
+
init_writeable_data();
|
|
3190
|
+
init_exceptions();
|
|
3191
|
+
|
|
3192
|
+
class WriteHashMap extends ReadHashMap {
|
|
3193
|
+
constructor() {
|
|
3194
|
+
super();
|
|
3195
|
+
}
|
|
3196
|
+
static async create(cursor) {
|
|
3197
|
+
const map = new WriteHashMap;
|
|
3198
|
+
const newCursor = await cursor.writePath([new HashMapInit(false, false)]);
|
|
3199
|
+
map.cursor = newCursor;
|
|
3200
|
+
return map;
|
|
3201
|
+
}
|
|
3202
|
+
iterator() {
|
|
3203
|
+
return this.cursor.iterator();
|
|
3204
|
+
}
|
|
3205
|
+
async* [Symbol.asyncIterator]() {
|
|
3206
|
+
yield* this.cursor;
|
|
3207
|
+
}
|
|
3208
|
+
async putByString(key, data) {
|
|
3209
|
+
const hash = await this.cursor.db.hasher.digest(new TextEncoder().encode(key));
|
|
3210
|
+
await this.putKey(hash, new Bytes(key));
|
|
3211
|
+
await this.put(hash, data);
|
|
3212
|
+
}
|
|
3213
|
+
async putCursorByString(key) {
|
|
3214
|
+
const hash = await this.cursor.db.hasher.digest(new TextEncoder().encode(key));
|
|
3215
|
+
await this.putKey(hash, new Bytes(key));
|
|
3216
|
+
return this.putCursor(hash);
|
|
3217
|
+
}
|
|
3218
|
+
async putKeyByString(key, data) {
|
|
3219
|
+
const hash = await this.cursor.db.hasher.digest(new TextEncoder().encode(key));
|
|
3220
|
+
await this.putKey(hash, data);
|
|
3221
|
+
}
|
|
3222
|
+
async putKeyCursorByString(key) {
|
|
3223
|
+
const hash = await this.cursor.db.hasher.digest(new TextEncoder().encode(key));
|
|
3224
|
+
return this.putKeyCursor(hash);
|
|
3225
|
+
}
|
|
3226
|
+
async removeByString(key) {
|
|
3227
|
+
const hash = await this.cursor.db.hasher.digest(new TextEncoder().encode(key));
|
|
3228
|
+
return this.remove(hash);
|
|
3229
|
+
}
|
|
3230
|
+
async putByBytes(key, data) {
|
|
3231
|
+
const hash = await this.cursor.db.hasher.digest(key.value);
|
|
3232
|
+
await this.putKey(hash, key);
|
|
3233
|
+
await this.put(hash, data);
|
|
3234
|
+
}
|
|
3235
|
+
async putCursorByBytes(key) {
|
|
3236
|
+
const hash = await this.cursor.db.hasher.digest(key.value);
|
|
3237
|
+
await this.putKey(hash, key);
|
|
3238
|
+
return this.putCursor(hash);
|
|
3239
|
+
}
|
|
3240
|
+
async putKeyByBytes(key, data) {
|
|
3241
|
+
const hash = await this.cursor.db.hasher.digest(key.value);
|
|
3242
|
+
await this.putKey(hash, data);
|
|
3243
|
+
}
|
|
3244
|
+
async putKeyCursorByBytes(key) {
|
|
3245
|
+
const hash = await this.cursor.db.hasher.digest(key.value);
|
|
3246
|
+
return this.putKeyCursor(hash);
|
|
3247
|
+
}
|
|
3248
|
+
async removeByBytes(key) {
|
|
3249
|
+
const hash = await this.cursor.db.hasher.digest(key.value);
|
|
3250
|
+
return this.remove(hash);
|
|
3251
|
+
}
|
|
3252
|
+
async put(hash, data) {
|
|
3253
|
+
await this.cursor.writePath([
|
|
3254
|
+
new HashMapGet(new HashMapGetValue(hash)),
|
|
3255
|
+
new WriteData(data)
|
|
3256
|
+
]);
|
|
3257
|
+
}
|
|
3258
|
+
async putCursor(hash) {
|
|
3259
|
+
return this.cursor.writePath([
|
|
3260
|
+
new HashMapGet(new HashMapGetValue(hash))
|
|
3261
|
+
]);
|
|
3262
|
+
}
|
|
3263
|
+
async putKey(hash, data) {
|
|
3264
|
+
const cursor = await this.cursor.writePath([
|
|
3265
|
+
new HashMapGet(new HashMapGetKey(hash))
|
|
3266
|
+
]);
|
|
3267
|
+
await cursor.writeIfEmpty(data);
|
|
3268
|
+
}
|
|
3269
|
+
async putKeyCursor(hash) {
|
|
3270
|
+
return this.cursor.writePath([
|
|
3271
|
+
new HashMapGet(new HashMapGetKey(hash))
|
|
3272
|
+
]);
|
|
3273
|
+
}
|
|
3274
|
+
async remove(hash) {
|
|
3275
|
+
try {
|
|
3276
|
+
await this.cursor.writePath([new HashMapRemove(hash)]);
|
|
3277
|
+
} catch (e) {
|
|
3278
|
+
if (e instanceof KeyNotFoundException) {
|
|
3279
|
+
return false;
|
|
3280
|
+
}
|
|
3281
|
+
throw e;
|
|
3282
|
+
}
|
|
3283
|
+
return true;
|
|
3284
|
+
}
|
|
3285
|
+
}
|
|
3286
|
+
// src/read-hash-set.ts
|
|
3287
|
+
init_tag();
|
|
3288
|
+
init_database();
|
|
3289
|
+
init_exceptions();
|
|
3290
|
+
|
|
3291
|
+
class ReadHashSet {
|
|
3292
|
+
cursor;
|
|
3293
|
+
constructor() {}
|
|
3294
|
+
static async create(cursor) {
|
|
3295
|
+
const set = new ReadHashSet;
|
|
3296
|
+
switch (cursor.slotPtr.slot.tag) {
|
|
3297
|
+
case 0 /* NONE */:
|
|
3298
|
+
case 4 /* HASH_MAP */:
|
|
3299
|
+
case 11 /* HASH_SET */:
|
|
3300
|
+
set.cursor = cursor;
|
|
3301
|
+
break;
|
|
3302
|
+
default:
|
|
3303
|
+
throw new UnexpectedTagException;
|
|
3304
|
+
}
|
|
3305
|
+
return set;
|
|
3306
|
+
}
|
|
3307
|
+
slot() {
|
|
3308
|
+
return this.cursor.slot();
|
|
3309
|
+
}
|
|
3310
|
+
iterator() {
|
|
3311
|
+
return this.cursor.iterator();
|
|
3312
|
+
}
|
|
3313
|
+
async* [Symbol.asyncIterator]() {
|
|
3314
|
+
yield* this.cursor;
|
|
3315
|
+
}
|
|
3316
|
+
async getCursorByString(key) {
|
|
3317
|
+
const hash = await this.cursor.db.hasher.digest(new TextEncoder().encode(key));
|
|
3318
|
+
return this.getCursor(hash);
|
|
3319
|
+
}
|
|
3320
|
+
async getSlotByString(key) {
|
|
3321
|
+
const hash = await this.cursor.db.hasher.digest(new TextEncoder().encode(key));
|
|
3322
|
+
return this.getSlot(hash);
|
|
3323
|
+
}
|
|
3324
|
+
async getCursorByBytes(key) {
|
|
3325
|
+
const hash = await this.cursor.db.hasher.digest(key.value);
|
|
3326
|
+
return this.getCursor(hash);
|
|
3327
|
+
}
|
|
3328
|
+
async getSlotByBytes(key) {
|
|
3329
|
+
const hash = await this.cursor.db.hasher.digest(key.value);
|
|
3330
|
+
return this.getSlot(hash);
|
|
3331
|
+
}
|
|
3332
|
+
async getCursor(hash) {
|
|
3333
|
+
return this.cursor.readPath([new HashMapGet(new HashMapGetKey(hash))]);
|
|
3334
|
+
}
|
|
3335
|
+
async getSlot(hash) {
|
|
3336
|
+
return this.cursor.readPathSlot([new HashMapGet(new HashMapGetKey(hash))]);
|
|
3337
|
+
}
|
|
3338
|
+
}
|
|
3339
|
+
// src/write-hash-set.ts
|
|
3340
|
+
init_database();
|
|
3341
|
+
init_writeable_data();
|
|
3342
|
+
init_exceptions();
|
|
3343
|
+
|
|
3344
|
+
class WriteHashSet extends ReadHashSet {
|
|
3345
|
+
constructor() {
|
|
3346
|
+
super();
|
|
3347
|
+
}
|
|
3348
|
+
static async create(cursor) {
|
|
3349
|
+
const set = new WriteHashSet;
|
|
3350
|
+
const newCursor = await cursor.writePath([new HashMapInit(false, true)]);
|
|
3351
|
+
set.cursor = newCursor;
|
|
3352
|
+
return set;
|
|
3353
|
+
}
|
|
3354
|
+
iterator() {
|
|
3355
|
+
return this.cursor.iterator();
|
|
3356
|
+
}
|
|
3357
|
+
async* [Symbol.asyncIterator]() {
|
|
3358
|
+
yield* this.cursor;
|
|
3359
|
+
}
|
|
3360
|
+
async putByString(key) {
|
|
3361
|
+
const bytes = new TextEncoder().encode(key);
|
|
3362
|
+
const hash = await this.cursor.db.hasher.digest(bytes);
|
|
3363
|
+
await this.put(hash, new Bytes(bytes));
|
|
3364
|
+
}
|
|
3365
|
+
async putCursorByString(key) {
|
|
3366
|
+
const hash = await this.cursor.db.hasher.digest(new TextEncoder().encode(key));
|
|
3367
|
+
return this.putCursor(hash);
|
|
3368
|
+
}
|
|
3369
|
+
async removeByString(key) {
|
|
3370
|
+
const hash = await this.cursor.db.hasher.digest(new TextEncoder().encode(key));
|
|
3371
|
+
return this.remove(hash);
|
|
3372
|
+
}
|
|
3373
|
+
async putByBytes(key) {
|
|
3374
|
+
const hash = await this.cursor.db.hasher.digest(key.value);
|
|
3375
|
+
await this.put(hash, key);
|
|
3376
|
+
}
|
|
3377
|
+
async putCursorByBytes(key) {
|
|
3378
|
+
const hash = await this.cursor.db.hasher.digest(key.value);
|
|
3379
|
+
return this.putCursor(hash);
|
|
3380
|
+
}
|
|
3381
|
+
async removeByBytes(key) {
|
|
3382
|
+
const hash = await this.cursor.db.hasher.digest(key.value);
|
|
3383
|
+
return this.remove(hash);
|
|
3384
|
+
}
|
|
3385
|
+
async put(hash, data) {
|
|
3386
|
+
const cursor = await this.cursor.writePath([
|
|
3387
|
+
new HashMapGet(new HashMapGetKey(hash))
|
|
3388
|
+
]);
|
|
3389
|
+
await cursor.writeIfEmpty(data);
|
|
3390
|
+
}
|
|
3391
|
+
async putCursor(hash) {
|
|
3392
|
+
return this.cursor.writePath([
|
|
3393
|
+
new HashMapGet(new HashMapGetKey(hash))
|
|
3394
|
+
]);
|
|
3395
|
+
}
|
|
3396
|
+
async remove(hash) {
|
|
3397
|
+
try {
|
|
3398
|
+
await this.cursor.writePath([new HashMapRemove(hash)]);
|
|
3399
|
+
} catch (e) {
|
|
3400
|
+
if (e instanceof KeyNotFoundException) {
|
|
3401
|
+
return false;
|
|
3402
|
+
}
|
|
3403
|
+
throw e;
|
|
3404
|
+
}
|
|
3405
|
+
return true;
|
|
3406
|
+
}
|
|
3407
|
+
}
|
|
3408
|
+
// src/read-linked-array-list.ts
|
|
3409
|
+
init_tag();
|
|
3410
|
+
init_database();
|
|
3411
|
+
init_exceptions();
|
|
3412
|
+
|
|
3413
|
+
class ReadLinkedArrayList {
|
|
3414
|
+
cursor;
|
|
3415
|
+
constructor(cursor) {
|
|
3416
|
+
switch (cursor.slotPtr.slot.tag) {
|
|
3417
|
+
case 0 /* NONE */:
|
|
3418
|
+
case 3 /* LINKED_ARRAY_LIST */:
|
|
3419
|
+
this.cursor = cursor;
|
|
3420
|
+
break;
|
|
3421
|
+
default:
|
|
3422
|
+
throw new UnexpectedTagException;
|
|
3423
|
+
}
|
|
3424
|
+
}
|
|
3425
|
+
slot() {
|
|
3426
|
+
return this.cursor.slot();
|
|
3427
|
+
}
|
|
3428
|
+
async count() {
|
|
3429
|
+
return this.cursor.count();
|
|
3430
|
+
}
|
|
3431
|
+
iterator() {
|
|
3432
|
+
return this.cursor.iterator();
|
|
3433
|
+
}
|
|
3434
|
+
async* [Symbol.asyncIterator]() {
|
|
3435
|
+
yield* this.cursor;
|
|
3436
|
+
}
|
|
3437
|
+
async getCursor(index) {
|
|
3438
|
+
return this.cursor.readPath([new LinkedArrayListGet(index)]);
|
|
3439
|
+
}
|
|
3440
|
+
async getSlot(index) {
|
|
3441
|
+
return this.cursor.readPathSlot([new LinkedArrayListGet(index)]);
|
|
3442
|
+
}
|
|
3443
|
+
}
|
|
3444
|
+
// src/write-linked-array-list.ts
|
|
3445
|
+
init_database();
|
|
3446
|
+
|
|
3447
|
+
class WriteLinkedArrayList extends ReadLinkedArrayList {
|
|
3448
|
+
constructor(cursor) {
|
|
3449
|
+
super(cursor);
|
|
3450
|
+
}
|
|
3451
|
+
static async create(cursor) {
|
|
3452
|
+
const newCursor = await cursor.writePath([new LinkedArrayListInit]);
|
|
3453
|
+
return new WriteLinkedArrayList(newCursor);
|
|
3454
|
+
}
|
|
3455
|
+
iterator() {
|
|
3456
|
+
return this.cursor.iterator();
|
|
3457
|
+
}
|
|
3458
|
+
async* [Symbol.asyncIterator]() {
|
|
3459
|
+
yield* this.cursor;
|
|
3460
|
+
}
|
|
3461
|
+
async put(index, data) {
|
|
3462
|
+
await this.cursor.writePath([
|
|
3463
|
+
new LinkedArrayListGet(index),
|
|
3464
|
+
new WriteData(data)
|
|
3465
|
+
]);
|
|
3466
|
+
}
|
|
3467
|
+
async putCursor(index) {
|
|
3468
|
+
return this.cursor.writePath([new LinkedArrayListGet(index)]);
|
|
3469
|
+
}
|
|
3470
|
+
async append(data) {
|
|
3471
|
+
await this.cursor.writePath([
|
|
3472
|
+
new LinkedArrayListAppend,
|
|
3473
|
+
new WriteData(data)
|
|
3474
|
+
]);
|
|
3475
|
+
}
|
|
3476
|
+
async appendCursor() {
|
|
3477
|
+
return this.cursor.writePath([new LinkedArrayListAppend]);
|
|
3478
|
+
}
|
|
3479
|
+
async slice(offset, size) {
|
|
3480
|
+
await this.cursor.writePath([
|
|
3481
|
+
new LinkedArrayListSlice(offset, size)
|
|
3482
|
+
]);
|
|
3483
|
+
}
|
|
3484
|
+
async concat(list) {
|
|
3485
|
+
await this.cursor.writePath([new LinkedArrayListConcat(list)]);
|
|
3486
|
+
}
|
|
3487
|
+
async insert(index, data) {
|
|
3488
|
+
await this.cursor.writePath([
|
|
3489
|
+
new LinkedArrayListInsert(index),
|
|
3490
|
+
new WriteData(data)
|
|
3491
|
+
]);
|
|
3492
|
+
}
|
|
3493
|
+
async insertCursor(index) {
|
|
3494
|
+
return this.cursor.writePath([new LinkedArrayListInsert(index)]);
|
|
3495
|
+
}
|
|
3496
|
+
async remove(index) {
|
|
3497
|
+
await this.cursor.writePath([new LinkedArrayListRemove(index)]);
|
|
3498
|
+
}
|
|
3499
|
+
}
|
|
3500
|
+
// src/read-counted-hash-map.ts
|
|
3501
|
+
init_tag();
|
|
3502
|
+
init_exceptions();
|
|
3503
|
+
|
|
3504
|
+
class ReadCountedHashMap extends ReadHashMap {
|
|
3505
|
+
constructor() {
|
|
3506
|
+
super();
|
|
3507
|
+
}
|
|
3508
|
+
static async create(cursor) {
|
|
3509
|
+
const map = new ReadCountedHashMap;
|
|
3510
|
+
switch (cursor.slotPtr.slot.tag) {
|
|
3511
|
+
case 0 /* NONE */:
|
|
3512
|
+
case 12 /* COUNTED_HASH_MAP */:
|
|
3513
|
+
case 13 /* COUNTED_HASH_SET */:
|
|
3514
|
+
map.cursor = cursor;
|
|
3515
|
+
break;
|
|
3516
|
+
default:
|
|
3517
|
+
throw new UnexpectedTagException;
|
|
3518
|
+
}
|
|
3519
|
+
return map;
|
|
3520
|
+
}
|
|
3521
|
+
async count() {
|
|
3522
|
+
return this.cursor.count();
|
|
3523
|
+
}
|
|
3524
|
+
}
|
|
3525
|
+
// src/write-counted-hash-map.ts
|
|
3526
|
+
init_tag();
|
|
3527
|
+
init_database();
|
|
3528
|
+
init_exceptions();
|
|
3529
|
+
|
|
3530
|
+
class WriteCountedHashMap extends WriteHashMap {
|
|
3531
|
+
constructor() {
|
|
3532
|
+
super();
|
|
3533
|
+
}
|
|
3534
|
+
static async create(cursor) {
|
|
3535
|
+
const map = new WriteCountedHashMap;
|
|
3536
|
+
switch (cursor.slotPtr.slot.tag) {
|
|
3537
|
+
case 0 /* NONE */:
|
|
3538
|
+
case 12 /* COUNTED_HASH_MAP */:
|
|
3539
|
+
case 13 /* COUNTED_HASH_SET */: {
|
|
3540
|
+
const newCursor = await cursor.writePath([new HashMapInit(true, false)]);
|
|
3541
|
+
map.cursor = newCursor;
|
|
3542
|
+
break;
|
|
3543
|
+
}
|
|
3544
|
+
default:
|
|
3545
|
+
throw new UnexpectedTagException;
|
|
3546
|
+
}
|
|
3547
|
+
return map;
|
|
3548
|
+
}
|
|
3549
|
+
async count() {
|
|
3550
|
+
return this.cursor.count();
|
|
3551
|
+
}
|
|
3552
|
+
}
|
|
3553
|
+
// src/read-counted-hash-set.ts
|
|
3554
|
+
init_tag();
|
|
3555
|
+
init_exceptions();
|
|
3556
|
+
|
|
3557
|
+
class ReadCountedHashSet extends ReadHashSet {
|
|
3558
|
+
constructor() {
|
|
3559
|
+
super();
|
|
3560
|
+
}
|
|
3561
|
+
static async create(cursor) {
|
|
3562
|
+
const set = new ReadCountedHashSet;
|
|
3563
|
+
switch (cursor.slotPtr.slot.tag) {
|
|
3564
|
+
case 0 /* NONE */:
|
|
3565
|
+
case 12 /* COUNTED_HASH_MAP */:
|
|
3566
|
+
case 13 /* COUNTED_HASH_SET */:
|
|
3567
|
+
set.cursor = cursor;
|
|
3568
|
+
break;
|
|
3569
|
+
default:
|
|
3570
|
+
throw new UnexpectedTagException;
|
|
3571
|
+
}
|
|
3572
|
+
return set;
|
|
3573
|
+
}
|
|
3574
|
+
async count() {
|
|
3575
|
+
return this.cursor.count();
|
|
3576
|
+
}
|
|
3577
|
+
}
|
|
3578
|
+
// src/write-counted-hash-set.ts
|
|
3579
|
+
init_tag();
|
|
3580
|
+
init_database();
|
|
3581
|
+
init_exceptions();
|
|
3582
|
+
|
|
3583
|
+
class WriteCountedHashSet extends WriteHashSet {
|
|
3584
|
+
constructor() {
|
|
3585
|
+
super();
|
|
3586
|
+
}
|
|
3587
|
+
static async create(cursor) {
|
|
3588
|
+
const set = new WriteCountedHashSet;
|
|
3589
|
+
switch (cursor.slotPtr.slot.tag) {
|
|
3590
|
+
case 0 /* NONE */:
|
|
3591
|
+
case 12 /* COUNTED_HASH_MAP */:
|
|
3592
|
+
case 13 /* COUNTED_HASH_SET */: {
|
|
3593
|
+
const newCursor = await cursor.writePath([new HashMapInit(true, true)]);
|
|
3594
|
+
set.cursor = newCursor;
|
|
3595
|
+
break;
|
|
3596
|
+
}
|
|
3597
|
+
default:
|
|
3598
|
+
throw new UnexpectedTagException;
|
|
3599
|
+
}
|
|
3600
|
+
return set;
|
|
3601
|
+
}
|
|
3602
|
+
async count() {
|
|
3603
|
+
return this.cursor.count();
|
|
3604
|
+
}
|
|
3605
|
+
}
|
|
3606
|
+
export {
|
|
3607
|
+
tagValueOf,
|
|
3608
|
+
Writer,
|
|
3609
|
+
WriteNotAllowedException,
|
|
3610
|
+
WriteMode,
|
|
3611
|
+
WriteLinkedArrayList,
|
|
3612
|
+
WriteKeyValuePairCursor,
|
|
3613
|
+
WriteHashSet,
|
|
3614
|
+
WriteHashMap,
|
|
3615
|
+
WriteData,
|
|
3616
|
+
WriteCursorIterator,
|
|
3617
|
+
WriteCursor,
|
|
3618
|
+
WriteCountedHashSet,
|
|
3619
|
+
WriteCountedHashMap,
|
|
3620
|
+
WriteArrayList,
|
|
3621
|
+
VERSION,
|
|
3622
|
+
UnreachableException,
|
|
3623
|
+
UnexpectedWriterPositionException,
|
|
3624
|
+
UnexpectedTagException,
|
|
3625
|
+
Uint,
|
|
3626
|
+
TopLevelArrayListHeader,
|
|
3627
|
+
Tag,
|
|
3628
|
+
StreamTooLongException,
|
|
3629
|
+
SlotPointer,
|
|
3630
|
+
Slot,
|
|
3631
|
+
SLOT_COUNT,
|
|
3632
|
+
Reader,
|
|
3633
|
+
ReadLinkedArrayList,
|
|
3634
|
+
ReadHashSet,
|
|
3635
|
+
ReadHashMap,
|
|
3636
|
+
ReadCursor,
|
|
3637
|
+
ReadCountedHashSet,
|
|
3638
|
+
ReadCountedHashMap,
|
|
3639
|
+
ReadArrayList,
|
|
3640
|
+
RandomAccessMemory,
|
|
3641
|
+
PathPartMustBeAtEndException,
|
|
3642
|
+
NotImplementedException,
|
|
3643
|
+
NoAvailableSlotsException,
|
|
3644
|
+
MustSetNewSlotsToFullException,
|
|
3645
|
+
MaxShiftExceededException,
|
|
3646
|
+
MAX_BRANCH_LENGTH,
|
|
3647
|
+
MASK,
|
|
3648
|
+
MAGIC_NUMBER,
|
|
3649
|
+
LinkedArrayListSlotPointer,
|
|
3650
|
+
LinkedArrayListSlot2 as LinkedArrayListSlot,
|
|
3651
|
+
LinkedArrayListSlice,
|
|
3652
|
+
LinkedArrayListRemove,
|
|
3653
|
+
LinkedArrayListInsert,
|
|
3654
|
+
LinkedArrayListInit,
|
|
3655
|
+
LinkedArrayListHeader,
|
|
3656
|
+
LinkedArrayListGet,
|
|
3657
|
+
LinkedArrayListConcat,
|
|
3658
|
+
LinkedArrayListBlockInfo,
|
|
3659
|
+
LinkedArrayListAppend,
|
|
3660
|
+
LINKED_ARRAY_LIST_INDEX_BLOCK_SIZE,
|
|
3661
|
+
KeyValuePairCursor,
|
|
3662
|
+
KeyValuePair,
|
|
3663
|
+
KeyOffsetExceededException,
|
|
3664
|
+
KeyNotFoundException,
|
|
3665
|
+
InvalidVersionException,
|
|
3666
|
+
InvalidTopLevelTypeException,
|
|
3667
|
+
InvalidOffsetException,
|
|
3668
|
+
InvalidHashSizeException,
|
|
3669
|
+
InvalidFormatTagSizeException,
|
|
3670
|
+
InvalidDatabaseException,
|
|
3671
|
+
Int,
|
|
3672
|
+
INDEX_BLOCK_SIZE,
|
|
3673
|
+
Header,
|
|
3674
|
+
Hasher,
|
|
3675
|
+
HashMapRemove,
|
|
3676
|
+
HashMapInit,
|
|
3677
|
+
HashMapGetValue,
|
|
3678
|
+
HashMapGetKey,
|
|
3679
|
+
HashMapGetKVPair,
|
|
3680
|
+
HashMapGet,
|
|
3681
|
+
Float,
|
|
3682
|
+
ExpectedUnsignedLongException,
|
|
3683
|
+
ExpectedTxStartException,
|
|
3684
|
+
ExpectedRootNodeException,
|
|
3685
|
+
EndOfStreamException,
|
|
3686
|
+
EmptySlotException,
|
|
3687
|
+
DatabaseException,
|
|
3688
|
+
Database3 as Database,
|
|
3689
|
+
CursorNotWriteableException,
|
|
3690
|
+
CursorIterator,
|
|
3691
|
+
CoreMemory,
|
|
3692
|
+
CoreFile,
|
|
3693
|
+
Context,
|
|
3694
|
+
Bytes,
|
|
3695
|
+
BIT_COUNT,
|
|
3696
|
+
ArrayListSlice,
|
|
3697
|
+
ArrayListInit,
|
|
3698
|
+
ArrayListHeader,
|
|
3699
|
+
ArrayListGet2 as ArrayListGet,
|
|
3700
|
+
ArrayListAppend
|
|
3701
|
+
};
|