UNPKG

@tai-kun/surrealdb

Version:

The SurrealDB SDK for JavaScript

169 lines (139 loc) 4.49 kB
import type { Uint8ArrayLike } from "@tai-kun/surrealdb/types"; import type { AllocatedMemoryBlock } from "./_memory"; export interface WriterOptions { readonly maxDepth?: number | undefined; } export class Writer { readonly maxDepth: number; constructor( memory: AllocatedMemoryBlock, options: WriterOptions | undefined = {}, ) { const { maxDepth = 64, } = options; this.maxDepth = maxDepth; this.data = memory.data; this.view = memory.view; this.depth = 0; this.total = 0; this.offset = 0; this.chunks = [memory.data]; this.memory = memory; } data: Uint8Array; view: DataView; depth: number; total: number; offset: number; protected chunks: [Uint8Array, ...Uint8Array[]]; protected readonly memory: AllocatedMemoryBlock; protected datacopy(): Uint8Array { return this.offset >= this.data.length ? this.data.slice() : this.data.slice(0, this.offset); } protected dataref(): Uint8Array { if (this.offset <= this.data.length) { return this.data.subarray(0, this.offset); // trim } return this.data; } claim(size: number): void { if (size > this.memory.size) { // 事前に用意されたメモリーサイズを超える要求があれば: // (1) 現チャンクに内容があれば必要なだけ複製を記録する。 // (2) 要求サイズちょうどのデータを作成する。 // (3) 総容量を更新する。 // (4) オフセットを 0 に戻す。 let last = this.chunks.length - 1; // (1) if (this.offset > 0) { this.chunks[last++] = this.datacopy(); } this.data = this.chunks[last] = new Uint8Array(size); // (2) this.view = new DataView(this.data.buffer, 0, size); // (2) this.total += this.offset; // (3) this.offset = 0; // (4) } else if (size > (this.data.length - this.offset)) { // 要求サイズがチャンクに収まらない場合: // (1) 現チャンクが事前に用意されたメモリーなら必要なだけ複製を記録する。 // (2) 現チャンクがカスタムサイズのメモリーなら必要なだけ参照を記録する。 // (3) 現チャンクを事前に用意されたメモリーにする。 // (4) 総容量を更新する。 // (5) オフセットを 0 に戻す。 const last = this.chunks.length - 1; // (1) if (this.data === this.memory.data) { this.chunks[last] = this.datacopy(); } // // (2) else if (this.data.length < this.offset) { this.chunks[last] = this.dataref(); } this.data = this.chunks[last + 1] = this.memory.data; // (3) this.view = this.memory.view; // (3) this.total += this.offset; // (4) this.offset = 0; // (5) } } output(): Uint8Array { if (this.chunks.length < 2) { if (this.data === this.memory.data) { return this.datacopy(); } return this.data; } const last = this.chunks.length - 1; this.chunks[last] = this.dataref(); // コピーされるので参照で構わない。 const acc = new Uint8Array(this.total + this.offset); for ( let offset = 0, chunk: Uint8Array | undefined; (chunk = this.chunks.shift()); ) { acc.set(chunk, offset); offset += chunk.length; } return acc; } writeBytes(value: Uint8ArrayLike): void { this.claim(value.length); this.data.set(value, this.offset); this.offset += value.length; } writeUint8(value: number): void { this.claim(1); this.view.setUint8(this.offset, value); this.offset += 1; } writeUint16(value: number): void { this.claim(2); this.view.setUint16(this.offset, value); this.offset += 2; } writeUint32(value: number): void { this.claim(4); this.view.setUint32(this.offset, value); this.offset += 4; } writeBigUint64(value: bigint): void { this.claim(8); this.view.setBigUint64(this.offset, value); this.offset += 8; } // writeFloat16(value: number): void { // this.claim(2); // setFloat16(this.view, this.offset, value); // this.offset += 2; // } writeFloat32(value: number): void { this.claim(4); this.view.setFloat32(this.offset, value); this.offset += 4; } writeFloat64(value: number): void { this.claim(8); this.view.setFloat64(this.offset, value); this.offset += 8; } }