From ba7221ae105cd58855d84bdf0ce66eb87a60c3a7 Mon Sep 17 00:00:00 2001 From: "D. Berge" Date: Wed, 30 Jul 2025 17:41:17 +0200 Subject: [PATCH] Implement `getData*()` functions in `DougalBinaryBundle` --- lib/modules/@dougal/binary/classes.js | 192 +++++++++++++++++++++++++- 1 file changed, 190 insertions(+), 2 deletions(-) diff --git a/lib/modules/@dougal/binary/classes.js b/lib/modules/@dougal/binary/classes.js index f740587..a7354cc 100644 --- a/lib/modules/@dougal/binary/classes.js +++ b/lib/modules/@dougal/binary/classes.js @@ -40,6 +40,22 @@ function readTypedValue(view, offset, type) { } } +function writeTypedValue(view, offset, value, type) { + switch (type) { + case Int8Array: view.setInt8(offset, value); break; + case Uint8Array: view.setUint8(offset, value); break; + case Int16Array: view.setInt16(offset, value, true); break; + case Uint16Array: view.setUint16(offset, value, true); break; + case Int32Array: view.setInt32(offset, value, true); break; + case Uint32Array: view.setUint32(offset, value, true); break; + case Float32Array: view.setFloat32(offset, value, true); break; + case Float64Array: view.setFloat64(offset, value, true); break; + case BigInt64Array: view.setBigInt64(offset, BigInt(value), true); break; + case BigUint64Array: view.setBigUint64(offset, BigInt(value), true); break; + default: throw new Error(`Unsupported type: ${type.name}`); + } +} + class DougalBinaryBundle extends ArrayBuffer { static HEADER_LENGTH = 4; // Length of a bundle header @@ -295,7 +311,107 @@ class DougalBinaryBundle extends ArrayBuffer { * */ getDataSequentially () { - // TODO + const chunks = this.chunks(); + if (chunks.length === 0) return new ArrayBuffer(0); + + const firstChunk = chunks[0]; + const ΔelemC = firstChunk.ΔelemCount; + const elemC = firstChunk.elemCount; + + // Check consistency across chunks + for (const chunk of chunks) { + if (chunk.ΔelemCount !== ΔelemC || chunk.elemCount !== elemC) { + throw new Error('Inconsistent chunk structures'); + } + } + + // Get types from first chunk + const view = new DataView(firstChunk); + const ΔelemBaseTypes = []; + for (let k = 0; k < ΔelemC; k++) { + const typeByte = view.getUint8(12 + k); + const baseCode = typeByte & 0xF; + const baseType = codeToType[baseCode]; + if (!baseType) throw new Error('Invalid base type code'); + ΔelemBaseTypes.push(baseType); + } + const elemTypes = []; + for (let k = 0; k < elemC; k++) { + const typeCode = view.getUint8(12 + ΔelemC + k); + const type = codeToType[typeCode]; + if (!type) throw new Error('Invalid elem type code'); + elemTypes.push(type); + } + + // Compute total records + const totalN = chunks.reduce((sum, c) => sum + c.jCount, 0); + + // Compute sizes + const size_i = totalN * 2; // Uint16 for i + const size_j = totalN * 4; // Int32 for j + let size_Δelems = 0; + for (const t of ΔelemBaseTypes) { + size_Δelems += totalN * typeToBytes[t.name]; + } + let size_elems = 0; + for (const t of elemTypes) { + size_elems += totalN * typeToBytes[t.name]; + } + const totalSize = size_i + size_j + size_Δelems + size_elems; + + const ab = new ArrayBuffer(totalSize); + const dv = new DataView(ab); + + // Write i's + let off = 0; + for (const chunk of chunks) { + const i = chunk.i; + for (let idx = 0; idx < chunk.jCount; idx++) { + dv.setUint16(off, i, true); + off += 2; + } + } + + // Write j's + off = size_i; + for (const chunk of chunks) { + const j0 = chunk.j0; + const Δj = chunk.Δj; + for (let idx = 0; idx < chunk.jCount; idx++) { + const j = j0 + idx * Δj; + dv.setInt32(off, j, true); + off += 4; + } + } + + // Write Δelems + off = size_i + size_j; + for (let m = 0; m < ΔelemC; m++) { + const type = ΔelemBaseTypes[m]; + const bytes = typeToBytes[type.name]; + for (const chunk of chunks) { + const arr = chunk.Δelem(m); + for (let idx = 0; idx < chunk.jCount; idx++) { + writeTypedValue(dv, off, arr[idx], type); + off += bytes; + } + } + } + + // Write elems + for (let m = 0; m < elemC; m++) { + const type = elemTypes[m]; + const bytes = typeToBytes[type.name]; + for (const chunk of chunks) { + const arr = chunk.elem(m); + for (let idx = 0; idx < chunk.jCount; idx++) { + writeTypedValue(dv, off, arr[idx], type); + off += bytes; + } + } + } + + return ab; } /** Return a ByteArray containing all data from all @@ -312,7 +428,79 @@ class DougalBinaryBundle extends ArrayBuffer { * */ getDataInterleaved () { - // TODO + const chunks = this.chunks(); + if (chunks.length === 0) return new ArrayBuffer(0); + + const firstChunk = chunks[0]; + const ΔelemC = firstChunk.ΔelemCount; + const elemC = firstChunk.elemCount; + + // Check consistency across chunks + for (const chunk of chunks) { + if (chunk.ΔelemCount !== ΔelemC || chunk.elemCount !== elemC) { + throw new Error('Inconsistent chunk structures'); + } + } + + // Get types from first chunk + const view = new DataView(firstChunk); + const ΔelemBaseTypes = []; + for (let k = 0; k < ΔelemC; k++) { + const typeByte = view.getUint8(12 + k); + const baseCode = typeByte & 0xF; + const baseType = codeToType[baseCode]; + if (!baseType) throw new Error('Invalid base type code'); + ΔelemBaseTypes.push(baseType); + } + const elemTypes = []; + for (let k = 0; k < elemC; k++) { + const typeCode = view.getUint8(12 + ΔelemC + k); + const type = codeToType[typeCode]; + if (!type) throw new Error('Invalid elem type code'); + elemTypes.push(type); + } + + // Compute total records + const totalN = chunks.reduce((sum, c) => sum + c.jCount, 0); + + // Compute record size + const recordSize = 2 + 4 + // i (Uint16) + j (Int32) + ΔelemBaseTypes.reduce((sum, t) => sum + typeToBytes[t.name], 0) + + elemTypes.reduce((sum, t) => sum + typeToBytes[t.name], 0); + const totalSize = totalN * recordSize; + + const ab = new ArrayBuffer(totalSize); + const dv = new DataView(ab); + + let off = 0; + for (const chunk of chunks) { + const i = chunk.i; + const j0 = chunk.j0; + const Δj = chunk.Δj; + for (let idx = 0; idx < chunk.jCount; idx++) { + dv.setUint16(off, i, true); + off += 2; + const j = j0 + idx * Δj; + dv.setInt32(off, j, true); + off += 4; + for (let m = 0; m < ΔelemC; m++) { + const type = ΔelemBaseTypes[m]; + const bytes = typeToBytes[type.name]; + const arr = chunk.Δelem(m); + writeTypedValue(dv, off, arr[idx], type); + off += bytes; + } + for (let m = 0; m < elemC; m++) { + const type = elemTypes[m]; + const bytes = typeToBytes[type.name]; + const arr = chunk.elem(m); + writeTypedValue(dv, off, arr[idx], type); + off += bytes; + } + } + } + + return ab; } }