mirror of
https://github.com/google/flatbuffers.git
synced 2026-06-25 02:56:09 +00:00
[TS/JS] BigInt implementation (#6998)
* BigInt implementation * Unit test reading long from existing bytebuffer * Code review
This commit is contained in:
@@ -1,7 +1,6 @@
|
||||
import { ByteBuffer } from "./byte-buffer"
|
||||
import { SIZEOF_SHORT, SIZE_PREFIX_LENGTH, SIZEOF_INT, FILE_IDENTIFIER_LENGTH } from "./constants"
|
||||
import { Offset, IGeneratedObject } from "./types"
|
||||
import { Long } from "./long"
|
||||
|
||||
export class Builder {
|
||||
private bb: ByteBuffer
|
||||
@@ -136,7 +135,7 @@ export class Builder {
|
||||
this.bb.writeInt32(this.space -= 4, value);
|
||||
}
|
||||
|
||||
writeInt64(value: Long): void {
|
||||
writeInt64(value: bigint): void {
|
||||
this.bb.writeInt64(this.space -= 8, value);
|
||||
}
|
||||
|
||||
@@ -179,7 +178,7 @@ export class Builder {
|
||||
* Add an `int64` to the buffer, properly aligned, and grows the buffer (if necessary).
|
||||
* @param value The `int64` to add the the buffer.
|
||||
*/
|
||||
addInt64(value: Long): void {
|
||||
addInt64(value: bigint): void {
|
||||
this.prep(8, 0);
|
||||
this.writeInt64(value);
|
||||
}
|
||||
@@ -223,8 +222,8 @@ export class Builder {
|
||||
}
|
||||
}
|
||||
|
||||
addFieldInt64(voffset: number, value: Long, defaultValue: Long): void {
|
||||
if (this.force_defaults || !value.equals(defaultValue)) {
|
||||
addFieldInt64(voffset: number, value: bigint, defaultValue: bigint): void {
|
||||
if (this.force_defaults || value !== defaultValue) {
|
||||
this.addInt64(value);
|
||||
this.slot(voffset);
|
||||
}
|
||||
@@ -574,13 +573,6 @@ export class Builder {
|
||||
return this.endVector();
|
||||
}
|
||||
|
||||
/**
|
||||
* A helper function to avoid generated code depending on this file directly.
|
||||
*/
|
||||
createLong(low: number, high: number): Long {
|
||||
return Long.create(low, high);
|
||||
}
|
||||
|
||||
/**
|
||||
* A helper function to pack an object
|
||||
*
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
import { FILE_IDENTIFIER_LENGTH, SIZEOF_INT } from "./constants";
|
||||
import { Long } from "./long";
|
||||
import { int32, isLittleEndian, float32, float64 } from "./utils";
|
||||
import { Offset, Table, IGeneratedObject } from "./types";
|
||||
import { Encoding } from "./encoding";
|
||||
@@ -75,12 +74,12 @@ export class ByteBuffer {
|
||||
return this.readInt32(offset) >>> 0;
|
||||
}
|
||||
|
||||
readInt64(offset: number): Long {
|
||||
return new Long(this.readInt32(offset), this.readInt32(offset + 4));
|
||||
readInt64(offset: number): bigint {
|
||||
return BigInt.asIntN(64, BigInt(this.readUint32(offset)) + (BigInt(this.readUint32(offset + 4)) << BigInt(32)));
|
||||
}
|
||||
|
||||
readUint64(offset: number): Long {
|
||||
return new Long(this.readUint32(offset), this.readUint32(offset + 4));
|
||||
readUint64(offset: number): bigint {
|
||||
return BigInt.asUintN(64, BigInt(this.readUint32(offset)) + (BigInt(this.readUint32(offset + 4)) << BigInt(32)));
|
||||
}
|
||||
|
||||
readFloat32(offset: number): number {
|
||||
@@ -108,8 +107,8 @@ export class ByteBuffer {
|
||||
}
|
||||
|
||||
writeUint16(offset: number, value: number): void {
|
||||
this.bytes_[offset] = value;
|
||||
this.bytes_[offset + 1] = value >> 8;
|
||||
this.bytes_[offset] = value;
|
||||
this.bytes_[offset + 1] = value >> 8;
|
||||
}
|
||||
|
||||
writeInt32(offset: number, value: number): void {
|
||||
@@ -120,20 +119,20 @@ export class ByteBuffer {
|
||||
}
|
||||
|
||||
writeUint32(offset: number, value: number): void {
|
||||
this.bytes_[offset] = value;
|
||||
this.bytes_[offset + 1] = value >> 8;
|
||||
this.bytes_[offset + 2] = value >> 16;
|
||||
this.bytes_[offset + 3] = value >> 24;
|
||||
this.bytes_[offset] = value;
|
||||
this.bytes_[offset + 1] = value >> 8;
|
||||
this.bytes_[offset + 2] = value >> 16;
|
||||
this.bytes_[offset + 3] = value >> 24;
|
||||
}
|
||||
|
||||
writeInt64(offset: number, value: Long): void {
|
||||
this.writeInt32(offset, value.low);
|
||||
this.writeInt32(offset + 4, value.high);
|
||||
writeInt64(offset: number, value: bigint): void {
|
||||
this.writeInt32(offset, Number(BigInt.asIntN(32, value)));
|
||||
this.writeInt32(offset + 4, Number(BigInt.asIntN(32, value >> BigInt(32))));
|
||||
}
|
||||
|
||||
writeUint64(offset: number, value: Long): void {
|
||||
this.writeUint32(offset, value.low);
|
||||
this.writeUint32(offset + 4, value.high);
|
||||
writeUint64(offset: number, value: bigint): void {
|
||||
this.writeUint32(offset, Number(BigInt.asUintN(32, value)));
|
||||
this.writeUint32(offset + 4, Number(BigInt.asUintN(32, value >> BigInt(32))));
|
||||
}
|
||||
|
||||
writeFloat32(offset: number, value: number): void {
|
||||
@@ -301,14 +300,7 @@ export class ByteBuffer {
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* A helper function to avoid generated code depending on this file directly.
|
||||
*/
|
||||
createLong(low: number, high: number): Long {
|
||||
return Long.create(low, high);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* A helper function for generating list for obj api
|
||||
*/
|
||||
@@ -341,4 +333,4 @@ export class ByteBuffer {
|
||||
return ret;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -7,7 +7,6 @@ export { Table, Offset } from './types'
|
||||
|
||||
export { int32, float32, float64, isLittleEndian } from './utils'
|
||||
|
||||
export { Long, createLong } from './long'
|
||||
export { Encoding } from './encoding'
|
||||
export { Builder } from './builder'
|
||||
export { ByteBuffer } from './byte-buffer'
|
||||
|
||||
@@ -3,15 +3,13 @@ import { toByteWidth, fromByteWidth } from './bit-width-util'
|
||||
import { toUTF8Array, fromUTF8Array } from './flexbuffers-util'
|
||||
import { Reference } from './reference'
|
||||
|
||||
import { Long } from '../long'
|
||||
|
||||
export function validateOffset(dataView: DataView, offset: number, width: number): void {
|
||||
if (dataView.byteLength <= offset + width || (offset & (toByteWidth(width) - 1)) !== 0) {
|
||||
throw "Bad offset: " + offset + ", width: " + width;
|
||||
}
|
||||
}
|
||||
|
||||
export function readInt(dataView: DataView, offset: number, width: number): number | Long | bigint {
|
||||
export function readInt(dataView: DataView, offset: number, width: number): number | bigint {
|
||||
if (width < 2) {
|
||||
if (width < 1) {
|
||||
return dataView.getInt8(offset);
|
||||
@@ -23,14 +21,14 @@ export function readInt(dataView: DataView, offset: number, width: number): numb
|
||||
return dataView.getInt32(offset, true)
|
||||
} else {
|
||||
if (dataView.setBigInt64 === undefined) {
|
||||
return new Long(dataView.getUint32(offset, true), dataView.getUint32(offset + 4, true))
|
||||
return BigInt(dataView.getUint32(offset, true)) + (BigInt(dataView.getUint32(offset + 4, true)) << BigInt(32));
|
||||
}
|
||||
return dataView.getBigInt64(offset, true)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export function readUInt(dataView: DataView, offset: number, width: number): number | Long | bigint {
|
||||
export function readUInt(dataView: DataView, offset: number, width: number): number | bigint {
|
||||
if (width < 2) {
|
||||
if (width < 1) {
|
||||
return dataView.getUint8(offset);
|
||||
@@ -42,7 +40,7 @@ export function readUInt(dataView: DataView, offset: number, width: number): num
|
||||
return dataView.getUint32(offset, true)
|
||||
} else {
|
||||
if (dataView.getBigUint64 === undefined) {
|
||||
return new Long(dataView.getUint32(offset, true), dataView.getUint32(offset + 4, true))
|
||||
return BigInt(dataView.getUint32(offset, true)) + (BigInt(dataView.getUint32(offset + 4, true)) << BigInt(32));
|
||||
}
|
||||
return dataView.getBigUint64(offset, true)
|
||||
}
|
||||
@@ -116,4 +114,4 @@ export function keyForIndex(index: number, dataView: DataView, offset: number, p
|
||||
length++;
|
||||
}
|
||||
return fromUTF8Array(new Uint8Array(dataView.buffer, keyIndirectOffset, length));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,7 +2,6 @@ import { fromByteWidth } from './bit-width-util'
|
||||
import { ValueType } from './value-type'
|
||||
import { isNumber, isIndirectNumber, isAVector, fixedTypedVectorElementSize, isFixedTypedVector, isTypedVector, typedVectorElementType, packedType, fixedTypedVectorElementType } from './value-type-util'
|
||||
import { indirect, keyForIndex, keyIndex, readFloat, readInt, readUInt, valueForIndexWithKey } from './reference-util'
|
||||
import { Long } from '../long';
|
||||
import { fromUTF8Array } from './flexbuffers-util';
|
||||
import { BitWidth } from './bit-width';
|
||||
|
||||
@@ -48,7 +47,7 @@ export class Reference {
|
||||
return null;
|
||||
}
|
||||
|
||||
intValue(): number | Long | bigint | null {
|
||||
intValue(): number | bigint | null {
|
||||
if (this.valueType === ValueType.INT) {
|
||||
return readInt(this.dataView, this.offset, this.parentWidth);
|
||||
}
|
||||
@@ -74,7 +73,7 @@ export class Reference {
|
||||
return null;
|
||||
}
|
||||
|
||||
numericValue(): number | Long | bigint | null { return this.floatValue() || this.intValue()}
|
||||
numericValue(): number | bigint | null { return this.floatValue() || this.intValue()}
|
||||
|
||||
stringValue(): string | null {
|
||||
if (this.valueType === ValueType.STRING || this.valueType === ValueType.KEY) {
|
||||
|
||||
23
ts/long.ts
23
ts/long.ts
@@ -1,23 +0,0 @@
|
||||
export function createLong(low: number, high: number): Long {
|
||||
return Long.create(low, high);
|
||||
}
|
||||
|
||||
export class Long {
|
||||
static readonly ZERO = new Long(0, 0)
|
||||
low: number
|
||||
high: number
|
||||
constructor(low: number, high: number) {
|
||||
this.low = low | 0;
|
||||
this.high = high | 0;
|
||||
}
|
||||
static create(low: number, high: number): Long {
|
||||
// Special-case zero to avoid GC overhead for default values
|
||||
return low == 0 && high == 0 ? Long.ZERO : new Long(low, high);
|
||||
}
|
||||
toFloat64(): number {
|
||||
return (this.low >>> 0) + this.high * 0x100000000;
|
||||
}
|
||||
equals(other: Long): boolean {
|
||||
return this.low == other.low && this.high == other.high;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user