• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1import { 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}