1import { BitWidth } from './bit-width.js' 2import { toByteWidth, fromByteWidth } from './bit-width-util.js' 3import { toUTF8Array, fromUTF8Array } from './flexbuffers-util.js' 4 5export function validateOffset(dataView: DataView, offset: number, width: number): void { 6 if (dataView.byteLength <= offset + width || (offset & (toByteWidth(width) - 1)) !== 0) { 7 throw "Bad offset: " + offset + ", width: " + width; 8 } 9} 10 11export function readInt(dataView: DataView, offset: number, width: number): number | bigint { 12 if (width < 2) { 13 if (width < 1) { 14 return dataView.getInt8(offset); 15 } else { 16 return dataView.getInt16(offset, true); 17 } 18 } else { 19 if (width < 3) { 20 return dataView.getInt32(offset, true) 21 } else { 22 if (dataView.setBigInt64 === undefined) { 23 return BigInt(dataView.getUint32(offset, true)) + (BigInt(dataView.getUint32(offset + 4, true)) << BigInt(32)); 24 } 25 return dataView.getBigInt64(offset, true) 26 } 27 } 28} 29 30export function readUInt(dataView: DataView, offset: number, width: number): number | bigint { 31 if (width < 2) { 32 if (width < 1) { 33 return dataView.getUint8(offset); 34 } else { 35 return dataView.getUint16(offset, true); 36 } 37 } else { 38 if (width < 3) { 39 return dataView.getUint32(offset, true) 40 } else { 41 if (dataView.getBigUint64 === undefined) { 42 return BigInt(dataView.getUint32(offset, true)) + (BigInt(dataView.getUint32(offset + 4, true)) << BigInt(32)); 43 } 44 return dataView.getBigUint64(offset, true) 45 } 46 } 47} 48 49export function readFloat(dataView: DataView, offset: number, width: number): number { 50 if (width < BitWidth.WIDTH32) { 51 throw "Bad width: " + width; 52 } 53 if (width === BitWidth.WIDTH32) { 54 return dataView.getFloat32(offset, true); 55 } 56 return dataView.getFloat64(offset, true); 57} 58 59export function indirect(dataView: DataView, offset: number, width: number): number { 60 const step = readUInt(dataView, offset, width) as number; 61 return offset - step; 62} 63 64export function keyIndex(key: string, dataView: DataView, offset: number, parentWidth: number, byteWidth: number, length: number): number | null { 65 const input = toUTF8Array(key); 66 const keysVectorOffset = indirect(dataView, offset, parentWidth) - byteWidth * 3; 67 const bitWidth = fromByteWidth(byteWidth); 68 const indirectOffset = keysVectorOffset - Number(readUInt(dataView, keysVectorOffset, bitWidth)); 69 const _byteWidth = Number(readUInt(dataView, keysVectorOffset + byteWidth, bitWidth)); 70 let low = 0; 71 let high = length - 1; 72 while (low <= high) { 73 const mid = (high + low) >> 1; 74 const dif = diffKeys(input, mid, dataView, indirectOffset, _byteWidth); 75 if (dif === 0) return mid; 76 if (dif < 0) { 77 high = mid - 1; 78 } else { 79 low = mid + 1; 80 } 81 } 82 return null; 83} 84 85export function diffKeys(input: Uint8Array, index: number, dataView: DataView, offset: number, width: number): number { 86 const keyOffset = offset + index * width; 87 const keyIndirectOffset = keyOffset - Number(readUInt(dataView, keyOffset, fromByteWidth(width))); 88 for (let i = 0; i < input.length; i++) { 89 const dif = input[i] - dataView.getUint8(keyIndirectOffset + i); 90 if (dif !== 0) { 91 return dif; 92 } 93 } 94 return dataView.getUint8(keyIndirectOffset + input.length) === 0 ? 0 : -1; 95} 96 97export function keyForIndex(index: number, dataView: DataView, offset: number, parentWidth: number, byteWidth: number): string { 98 const keysVectorOffset = indirect(dataView, offset, parentWidth) - byteWidth * 3; 99 const bitWidth = fromByteWidth(byteWidth); 100 const indirectOffset = keysVectorOffset - Number(readUInt(dataView, keysVectorOffset, bitWidth)); 101 const _byteWidth = Number(readUInt(dataView, keysVectorOffset + byteWidth, bitWidth)); 102 const keyOffset = indirectOffset + index * _byteWidth; 103 const keyIndirectOffset = keyOffset - Number(readUInt(dataView, keyOffset, fromByteWidth(_byteWidth))); 104 let length = 0; 105 while (dataView.getUint8(keyIndirectOffset + length) !== 0) { 106 length++; 107 } 108 return fromUTF8Array(new Uint8Array(dataView.buffer, keyIndirectOffset, length)); 109} 110