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