New Case Study:See how Anthropic automated 95% of dependency reviews with Socket.Learn More
Socket
Sign inDemoInstall
Socket

@bnaya/objectbuffer

Package Overview
Dependencies
Maintainers
1
Versions
122
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

@bnaya/objectbuffer - npm Package Compare versions

Comparing version 0.8.0 to 0.9.0

dist/internal/consts.d.ts

9

dist/internal/api.js

@@ -10,5 +10,6 @@ function ownKeys(object, enumerableOnly) { var keys = Object.keys(object); if (Object.getOwnPropertySymbols) { var symbols = Object.getOwnPropertySymbols(object); if (enumerableOnly) symbols = symbols.filter(function (sym) { return Object.getOwnPropertyDescriptor(object, sym).enumerable; }); keys.push.apply(keys, symbols); } return keys; }

import { createObjectWrapper } from "./objectWrapper";
import { GET_UNDERLYING_ARRAY_BUFFER_SYMBOL, REPLACE_DATA_VIEW_SYMBOL } from "./symbols";
import { INTERNAL_API_SYMBOL, REPLACE_DATA_VIEW_SYMBOL } from "./symbols";
import { arrayBufferCopyTo, getFirstFreeByte } from "./utils";
import { getCacheFor } from "./externalObjectsCache";
import { INITIAL_ENTRY_POINTER_TO_POINTER } from "./consts";

@@ -26,3 +27,3 @@ /**

} = objectSaver(externalArgsApiToExternalArgsApi(externalArgs), dataView, initialValue);
dataView.setUint32(16, start);
dataView.setUint32(INITIAL_ENTRY_POINTER_TO_POINTER, start);
return createObjectWrapper(externalArgsApiToExternalArgsApi(externalArgs), {

@@ -47,3 +48,3 @@ dataView

export function getUnderlyingArrayBuffer(objectBuffer) {
return objectBuffer[GET_UNDERLYING_ARRAY_BUFFER_SYMBOL];
return objectBuffer[INTERNAL_API_SYMBOL].getDataView().buffer;
}

@@ -64,3 +65,3 @@ /**

dataView
}, dataView.getUint32(16), true);
}, dataView.getUint32(INITIAL_ENTRY_POINTER_TO_POINTER), true);
}

@@ -67,0 +68,0 @@ /**

@@ -14,8 +14,5 @@ import { ExternalArgs, DataViewCarrier } from "./interfaces";

enumerable: boolean;
};
} | undefined;
has(target: {}, p: PropertyKey): boolean;
set(target: {}, p: PropertyKey, value: any): boolean;
isExtensible(): boolean;
preventExtensions(): boolean;
setPrototypeOf(): boolean;
set(target: {}, accessedProp: PropertyKey, value: any): boolean;
entries(): Iterable<[number, any]>;

@@ -30,4 +27,10 @@ keys(): Iterable<number>;

unshift(...elements: any): number;
getDataView(): DataView;
getEntryPointer(): number;
isExtensible(): boolean;
preventExtensions(): boolean;
setPrototypeOf(): boolean;
defineProperty(): boolean;
}
export declare function createArrayWrapper(externalArgs: ExternalArgs, dataViewCarrier: DataViewCarrier, entryPointer: number): Array<any>;
//# sourceMappingURL=arrayWrapper.d.ts.map
import { getFinalValueAtArrayIndex, arrayGetMetadata, setValueAtArrayIndex, arraySort, extendArrayIfNeeded, arrayReverse } from "./arrayHelpers";
import { GET_UNDERLYING_POINTER_SYMBOL } from "./symbols";
import { INTERNAL_API_SYMBOL } from "./symbols";
import { arraySplice } from "./arraySplice";
import { IllegalArrayIndexError, UnsupportedOperationError } from "./exceptions";
import { handleOOM } from "./handleOOM";
export class ArrayWrapper {

@@ -12,4 +14,4 @@ constructor(externalArgs, dataViewCarrier, entryPointer) {

get(target, p) {
if (p === GET_UNDERLYING_POINTER_SYMBOL) {
return this.entryPointer;
if (p === INTERNAL_API_SYMBOL) {
return this;
}

@@ -62,2 +64,6 @@

if (!this.has(target, prop)) {
return undefined;
}
return {

@@ -81,4 +87,8 @@ configurable: false,

set(target, p, value) {
if (p === "length") {
set(target, accessedProp, value) {
if (typeof accessedProp === "symbol") {
throw new IllegalArrayIndexError();
}
if (accessedProp === "length") {
if (!Number.isSafeInteger(value) || value < 0) {

@@ -94,28 +104,26 @@ throw new RangeError("Invalid array length");

if (currentLength > value) {
this.splice(value, currentLength - value);
return true;
}
handleOOM(() => {
if (currentLength > value) {
this.splice(value, currentLength - value);
return true;
}
extendArrayIfNeeded(this.externalArgs, this.dataViewCarrier.dataView, this.entryPointer, value);
extendArrayIfNeeded(this.externalArgs, this.dataViewCarrier.dataView, this.entryPointer, value);
}, this.dataViewCarrier.dataView);
return true;
}
extendArrayIfNeeded(this.externalArgs, this.dataViewCarrier.dataView, this.entryPointer, Number.parseInt(p, 10) + 1);
setValueAtArrayIndex(this.externalArgs, this.dataViewCarrier.dataView, this.entryPointer, Number.parseInt(p, 10), value);
return true;
}
const possibleIndex = Number.parseInt(accessedProp, 10);
isExtensible() {
if (!Number.isSafeInteger(possibleIndex) || possibleIndex < 0) {
throw new IllegalArrayIndexError();
}
handleOOM(() => {
extendArrayIfNeeded(this.externalArgs, this.dataViewCarrier.dataView, this.entryPointer, possibleIndex + 1);
setValueAtArrayIndex(this.externalArgs, this.dataViewCarrier.dataView, this.entryPointer, possibleIndex, value);
}, this.dataViewCarrier.dataView);
return true;
}
preventExtensions() {
throw new Error("unsupported");
}
setPrototypeOf() {
throw new Error("unsupported");
}
*entries() {

@@ -184,2 +192,34 @@ let index = 0;

getDataView() {
return this.dataViewCarrier.dataView;
}
getEntryPointer() {
return this.entryPointer;
}
isExtensible() {
return true;
}
preventExtensions() {
throw new UnsupportedOperationError();
}
setPrototypeOf() {
throw new UnsupportedOperationError();
}
defineProperty() {
throw new UnsupportedOperationError(); // if (
// typeof p === "symbol" ||
// attributes.enumerable === false ||
// attributes.get ||
// attributes.set
// ) {
// throw new IllegalObjectPropConfigError();
// }
// return Object.defineProperty(target, p, attributes);
}
}

@@ -186,0 +226,0 @@ export function createArrayWrapper(externalArgs, dataViewCarrier, entryPointer) {

@@ -12,4 +12,9 @@ import { ExternalArgs, DataViewCarrier } from "./interfaces";

private persistDateObject;
getDataView(): DataView;
getEntryPointer(): number;
defineProperty(): boolean;
setPrototypeOf(): boolean;
isExtensible(): boolean;
}
export declare function createDateWrapper(externalArgs: ExternalArgs, dataViewCarrier: DataViewCarrier, entryPointer: number): Date;
//# sourceMappingURL=dateWrapper.d.ts.map
import { readEntry, writeEntry } from "./store";
import { ENTRY_TYPE } from "./entry-types";
import { INTERNAL_API_SYMBOL } from "./symbols";
import { UnsupportedOperationError } from "./exceptions";
const getFunctions = ["toString", "toDateString", "toTimeString", "toISOString", "toUTCString", // "toGMTString",

@@ -18,2 +20,6 @@ "getDate", "getDay", "getFullYear", "getHours", "getMilliseconds", "getMinutes", "getMonth", "getSeconds", "getTime", "getTimezoneOffset", "getUTCDate", "getUTCDay", "getUTCFullYear", "getUTCHours", "getUTCMilliseconds", "getUTCMinutes", "getUTCMonth", "getUTCSeconds", // "getYear",

get(target, p) {
if (p === INTERNAL_API_SYMBOL) {
return this;
}
if (getFunctions.includes(p)) {

@@ -56,2 +62,22 @@ if (!(p in this.useMeToGiveNamesToFunctionsAndCacheThem)) {

getDataView() {
return this.dataViewCarrier.dataView;
}
getEntryPointer() {
return this.entryPointer;
}
defineProperty() {
throw new UnsupportedOperationError();
}
setPrototypeOf() {
throw new UnsupportedOperationError();
}
isExtensible() {
return false;
}
}

@@ -58,0 +84,0 @@ export function createDateWrapper(externalArgs, dataViewCarrier, entryPointer) {

@@ -5,4 +5,4 @@ export declare enum ENTRY_TYPE {

NUMBER = 2,
BIGINT = 3,
UBIGINT = 4,
BIGINT_POSITIVE = 3,
BIGINT_NEGATIVE = 4,
STRING = 5,

@@ -18,4 +18,4 @@ BOOLEAN = 6,

}
export declare const PRIMITIVE_TYPES: readonly [ENTRY_TYPE.NULL, ENTRY_TYPE.UNDEFINED, ENTRY_TYPE.NUMBER, ENTRY_TYPE.BIGINT, ENTRY_TYPE.UBIGINT, ENTRY_TYPE.BOOLEAN, ENTRY_TYPE.STRING];
export declare const isPrimitiveEntryType: (v: unknown) => v is ENTRY_TYPE.UNDEFINED | ENTRY_TYPE.NULL | ENTRY_TYPE.NUMBER | ENTRY_TYPE.BIGINT | ENTRY_TYPE.UBIGINT | ENTRY_TYPE.STRING | ENTRY_TYPE.BOOLEAN;
export declare const PRIMITIVE_TYPES: readonly [ENTRY_TYPE.NULL, ENTRY_TYPE.UNDEFINED, ENTRY_TYPE.NUMBER, ENTRY_TYPE.BIGINT_POSITIVE, ENTRY_TYPE.BIGINT_NEGATIVE, ENTRY_TYPE.BOOLEAN, ENTRY_TYPE.STRING];
export declare const isPrimitiveEntryType: (v: unknown) => v is ENTRY_TYPE.UNDEFINED | ENTRY_TYPE.NULL | ENTRY_TYPE.NUMBER | ENTRY_TYPE.BIGINT_POSITIVE | ENTRY_TYPE.BIGINT_NEGATIVE | ENTRY_TYPE.STRING | ENTRY_TYPE.BOOLEAN;
//# sourceMappingURL=entry-types.d.ts.map

@@ -8,4 +8,4 @@ import { createKnownTypeGuard } from "./utils";

ENTRY_TYPE[ENTRY_TYPE["NUMBER"] = 2] = "NUMBER";
ENTRY_TYPE[ENTRY_TYPE["BIGINT"] = 3] = "BIGINT";
ENTRY_TYPE[ENTRY_TYPE["UBIGINT"] = 4] = "UBIGINT";
ENTRY_TYPE[ENTRY_TYPE["BIGINT_POSITIVE"] = 3] = "BIGINT_POSITIVE";
ENTRY_TYPE[ENTRY_TYPE["BIGINT_NEGATIVE"] = 4] = "BIGINT_NEGATIVE";
ENTRY_TYPE[ENTRY_TYPE["STRING"] = 5] = "STRING";

@@ -22,3 +22,3 @@ ENTRY_TYPE[ENTRY_TYPE["BOOLEAN"] = 6] = "BOOLEAN";

export const PRIMITIVE_TYPES = [ENTRY_TYPE.NULL, ENTRY_TYPE.UNDEFINED, ENTRY_TYPE.NUMBER, ENTRY_TYPE.BIGINT, ENTRY_TYPE.UBIGINT, ENTRY_TYPE.BOOLEAN, ENTRY_TYPE.STRING];
export const PRIMITIVE_TYPES = [ENTRY_TYPE.NULL, ENTRY_TYPE.UNDEFINED, ENTRY_TYPE.NUMBER, ENTRY_TYPE.BIGINT_POSITIVE, ENTRY_TYPE.BIGINT_NEGATIVE, ENTRY_TYPE.BOOLEAN, ENTRY_TYPE.STRING];
export const isPrimitiveEntryType = createKnownTypeGuard(PRIMITIVE_TYPES);
import { ENTRY_TYPE } from "./entry-types";
import { TextDecoder, TextEncoder } from "./textEncoderDecoderTypes";
export declare type primitive = string | number | bigint | boolean | undefined | null;
export declare type Entry = NullEntry | NullUndefined | BooleanEntry | StringEntry | NumberEntry | BigIntEntry | UBigIntEntry | ObjectEntry | ObjectPropEntry | ArrayEntry | DateEntry;
export declare type Entry = NullEntry | NullUndefined | BooleanEntry | StringEntry | NumberEntry | BigIntPositiveEntry | BigIntNegativeEntry | ObjectEntry | ObjectPropEntry | ArrayEntry | DateEntry;
export interface NullEntry {

@@ -24,8 +24,8 @@ type: ENTRY_TYPE.NULL;

}
export interface BigIntEntry {
type: ENTRY_TYPE.BIGINT;
export interface BigIntPositiveEntry {
type: ENTRY_TYPE.BIGINT_POSITIVE;
value: bigint;
}
export interface UBigIntEntry {
type: ENTRY_TYPE.UBIGINT;
export interface BigIntNegativeEntry {
type: ENTRY_TYPE.BIGINT_NEGATIVE;
value: bigint;

@@ -79,2 +79,6 @@ }

}>;
export interface InternalAPI {
getDataView(): DataView;
getEntryPointer(): number;
}
//# sourceMappingURL=interfaces.d.ts.map

@@ -9,3 +9,2 @@ import { ExternalArgs, DataViewCarrier } from "./interfaces";

private replaceDataView;
private getUnderlyingArrayBuffer;
get(target: {}, p: PropertyKey): any;

@@ -15,6 +14,6 @@ deleteProperty(target: {}, p: PropertyKey): boolean;

ownKeys(): PropertyKey[];
getOwnPropertyDescriptor(): {
getOwnPropertyDescriptor(target: {}, p: PropertyKey): {
configurable: boolean;
enumerable: boolean;
};
} | undefined;
has(target: {}, p: PropertyKey): boolean;

@@ -25,5 +24,8 @@ set(target: {}, p: PropertyKey, value: any): boolean;

setPrototypeOf(): boolean;
defineProperty(): boolean;
private get entry();
getDataView(): DataView;
getEntryPointer(): number;
}
export declare function createObjectWrapper<T = any>(externalArgs: ExternalArgs, dataViewCarrier: DataViewCarrier, entryPointer: number, isTopLevel?: boolean): T;
//# sourceMappingURL=objectWrapper.d.ts.map

@@ -1,7 +0,6 @@

import { readEntry, writeEntry, appendEntry, overwriteEntryIfPossible } from "./store";
import { ENTRY_TYPE } from "./entry-types";
import { findObjectPropertyEntry, getObjectPropertiesEntries, deleteObjectPropertyEntryByKey, findLastObjectPropertyEntry } from "./objectWrapperHelpers";
import { saveValue } from "./saveValue";
import { entryToFinalJavaScriptValue } from "./entryToFinalJavaScriptValue";
import { GET_UNDERLYING_ARRAY_BUFFER_SYMBOL, GET_UNDERLYING_POINTER_SYMBOL, REPLACE_DATA_VIEW_SYMBOL } from "./symbols";
import { readEntry } from "./store";
import { findObjectPropertyEntry, getObjectPropertiesEntries, deleteObjectPropertyEntryByKey, objectGet, objectSet } from "./objectWrapperHelpers";
import { REPLACE_DATA_VIEW_SYMBOL, INTERNAL_API_SYMBOL } from "./symbols";
import { IllegalObjectPropConfigError, UnsupportedOperationError } from "./exceptions";
import { handleOOM } from "./handleOOM";
export class ObjectWrapper {

@@ -19,15 +18,3 @@ constructor(externalArgs, dataViewCarrier, entryPointer, isTopLevel) {

getUnderlyingArrayBuffer() {
if (!this.isTopLevel) {
throw new Error("Only Supported on Top Level");
}
return this.dataViewCarrier.dataView.buffer;
}
get(target, p) {
if (p === GET_UNDERLYING_ARRAY_BUFFER_SYMBOL) {
return this.getUnderlyingArrayBuffer();
}
if (p === REPLACE_DATA_VIEW_SYMBOL) {

@@ -37,4 +24,4 @@ return this.replaceDataView.bind(this);

if (p === GET_UNDERLYING_POINTER_SYMBOL) {
return this.entryPointer;
if (p === INTERNAL_API_SYMBOL) {
return this;
} /// empty object

@@ -47,13 +34,3 @@

const foundEntry = findObjectPropertyEntry(this.externalArgs, this.dataViewCarrier.dataView, this.entryPointer, // Add validation ?
// eslint-disable-next-line @typescript-eslint/ban-ts-ignore
// @ts-ignore
p);
if (foundEntry === undefined) {
return undefined;
}
const [valueEntry] = readEntry(this.externalArgs, this.dataViewCarrier.dataView, foundEntry[1].value.value);
return entryToFinalJavaScriptValue(this.externalArgs, this.dataViewCarrier.dataView, valueEntry, foundEntry[1].value.value);
return objectGet(this.externalArgs, this.dataViewCarrier.dataView, this.entryPointer, p);
}

@@ -75,11 +52,19 @@

getOwnPropertyDescriptor() {
return {
configurable: true,
enumerable: true
};
getOwnPropertyDescriptor(target, p) {
if (this.has(target, p)) {
return {
configurable: true,
enumerable: true
};
}
return undefined;
}
has(target, p) {
/// empty object
if (typeof p === "symbol") {
throw new IllegalObjectPropConfigError();
} /// empty object
if (this.entry.value === 0) {

@@ -89,6 +74,3 @@ return false;

const foundEntry = findObjectPropertyEntry(this.externalArgs, this.dataViewCarrier.dataView, this.entry.value, // Add validation ?
// eslint-disable-next-line @typescript-eslint/ban-ts-ignore
// @ts-ignore
p);
const foundEntry = findObjectPropertyEntry(this.externalArgs, this.dataViewCarrier.dataView, this.entryPointer, p);
return foundEntry !== undefined;

@@ -98,52 +80,9 @@ }

set(target, p, value) {
const foundPropEntry = findObjectPropertyEntry(this.externalArgs, this.dataViewCarrier.dataView, this.entryPointer, p); // new prop
if (foundPropEntry === undefined) {
const {
start: newValueEntryPointer
} = saveValue(this.externalArgs, this.dataViewCarrier.dataView, value);
const {
start: newPropEntryPointer
} = appendEntry(this.externalArgs, this.dataViewCarrier.dataView, {
type: ENTRY_TYPE.OBJECT_PROP,
value: {
next: 0,
value: newValueEntryPointer,
key: p
}
});
const [lastItemPointer, lastItemEntry] = findLastObjectPropertyEntry(this.externalArgs, this.dataViewCarrier.dataView, this.entryPointer);
if (lastItemEntry.type === ENTRY_TYPE.OBJECT) {
writeEntry(this.externalArgs, this.dataViewCarrier.dataView, lastItemPointer, {
type: ENTRY_TYPE.OBJECT,
value: newPropEntryPointer
});
} else {
writeEntry(this.externalArgs, this.dataViewCarrier.dataView, lastItemPointer, {
type: ENTRY_TYPE.OBJECT_PROP,
value: {
next: newPropEntryPointer,
value: lastItemEntry.value.value,
key: lastItemEntry.value.key
}
});
}
} else {
if (!overwriteEntryIfPossible(this.externalArgs, this.dataViewCarrier.dataView, foundPropEntry[1].value.value, value)) {
const {
start: newValueEntryPointer
} = saveValue(this.externalArgs, this.dataViewCarrier.dataView, value); // overwrite value
writeEntry(this.externalArgs, this.dataViewCarrier.dataView, foundPropEntry[0], {
type: ENTRY_TYPE.OBJECT_PROP,
value: {
key: foundPropEntry[1].value.key,
next: foundPropEntry[1].value.next,
value: newValueEntryPointer
}
});
}
if (typeof p === "symbol") {
throw new IllegalObjectPropConfigError();
}
handleOOM(() => {
objectSet(this.externalArgs, this.dataViewCarrier.dataView, this.entryPointer, p, value);
}, this.dataViewCarrier.dataView);
return true;

@@ -157,7 +96,7 @@ }

preventExtensions() {
throw new Error("unsupported");
throw new UnsupportedOperationError();
}
setPrototypeOf() {
throw new Error("unsupported");
throw new UnsupportedOperationError();
} // getPrototypeOf? (target: T): object | null;

@@ -172,4 +111,15 @@ // setPrototypeOf? (target: T, v: any): boolean;

// deleteProperty? (target: T, p: PropertyKey): boolean;
// defineProperty? (target: T, p: PropertyKey, attributes: PropertyDescriptor): boolean;
// enumerate? (target: T): PropertyKey[];
defineProperty() {
throw new UnsupportedOperationError(); // if (
// typeof p === "symbol" ||
// attributes.enumerable === false ||
// attributes.get ||
// attributes.set
// ) {
// throw new IllegalObjectPropConfigError();
// }
// return Object.defineProperty(target, p, attributes);
} // enumerate? (target: T): PropertyKey[];
// ownKeys? (target: T): PropertyKey[];

@@ -184,2 +134,10 @@ // apply? (target: T, thisArg: any, argArray?: any): any;

getDataView() {
return this.dataViewCarrier.dataView;
}
getEntryPointer() {
return this.entryPointer;
}
}

@@ -186,0 +144,0 @@ export function createObjectWrapper(externalArgs, dataViewCarrier, entryPointer, isTopLevel = false) {

@@ -13,2 +13,4 @@ import { ObjectEntry, ObjectPropEntry, ExternalArgs } from "./interfaces";

export declare function getObjectPropertiesEntries(externalArgs: ExternalArgs, dataView: DataView, containingObjectEntryPointer: number): ObjectPropEntry[];
export declare function objectSet(externalArgs: ExternalArgs, dataView: DataView, entryPointer: number, p: string, value: any): void;
export declare function objectGet(externalArgs: ExternalArgs, dataView: DataView, entryPointer: number, p: string): any;
//# sourceMappingURL=objectWrapperHelpers.d.ts.map

@@ -1,4 +0,6 @@

import { readEntry, writeEntry } from "./store";
import { readEntry, writeEntry, appendEntry, overwriteEntryIfPossible } from "./store";
import { invariant } from "./utils";
import { ENTRY_TYPE } from "./entry-types";
import { entryToFinalJavaScriptValue } from "./entryToFinalJavaScriptValue";
import { saveValue } from "./saveValue";
export function deleteObjectPropertyEntryByKey(externalArgs, dataView, containingObjectEntryPointer, keyToDeleteBy) {

@@ -83,10 +85,5 @@ invariant(containingObjectEntryPointer !== 0, "containingObjectEntryPointer Must not be 0");

let currentPointer = containingObjectEntry.value;
let objectPropEntry;
let objectPropEntry; // eslint-disable-next-line no-constant-condition
if (containingObjectEntry.value === 0) {
return undefined;
} // eslint-disable-next-line no-constant-condition
while (true) {
while (currentPointer !== 0) {
[objectPropEntry] = readEntry(externalArgs, dataView, currentPointer);

@@ -101,3 +98,3 @@

if (objectPropEntry.value.key === key) {
if (objectPropEntry && objectPropEntry.value.key === key) {
return [currentPointer, objectPropEntry];

@@ -110,2 +107,7 @@ }

const [containingObjectEntry] = readEntry(externalArgs, dataView, containingObjectEntryPointer);
if (containingObjectEntry.value === 0) {
return undefined;
}
let nextElementPointer = containingObjectEntry.value;

@@ -131,2 +133,6 @@ let objectPropEntry;

if (nextElementPointer === 0) {
return [];
}
do {

@@ -139,2 +145,63 @@ [objectPropEntry] = readEntry(externalArgs, dataView, nextElementPointer);

return foundProps;
}
export function objectSet(externalArgs, dataView, entryPointer, p, value) {
const foundPropEntry = findObjectPropertyEntry(externalArgs, dataView, entryPointer, p); // new prop
if (foundPropEntry === undefined) {
const {
start: newValueEntryPointer
} = saveValue(externalArgs, dataView, value);
const {
start: newPropEntryPointer
} = appendEntry(externalArgs, dataView, {
type: ENTRY_TYPE.OBJECT_PROP,
value: {
next: 0,
value: newValueEntryPointer,
key: p
}
});
const [lastItemPointer, lastItemEntry] = findLastObjectPropertyEntry(externalArgs, dataView, entryPointer);
if (lastItemEntry.type === ENTRY_TYPE.OBJECT) {
writeEntry(externalArgs, dataView, lastItemPointer, {
type: ENTRY_TYPE.OBJECT,
value: newPropEntryPointer
});
} else {
writeEntry(externalArgs, dataView, lastItemPointer, {
type: ENTRY_TYPE.OBJECT_PROP,
value: {
next: newPropEntryPointer,
value: lastItemEntry.value.value,
key: lastItemEntry.value.key
}
});
}
} else {
if (!overwriteEntryIfPossible(externalArgs, dataView, foundPropEntry[1].value.value, value)) {
const {
start: newValueEntryPointer
} = saveValue(externalArgs, dataView, value); // overwrite value
writeEntry(externalArgs, dataView, foundPropEntry[0], {
type: ENTRY_TYPE.OBJECT_PROP,
value: {
key: foundPropEntry[1].value.key,
next: foundPropEntry[1].value.next,
value: newValueEntryPointer
}
});
}
}
}
export function objectGet(externalArgs, dataView, entryPointer, p) {
const foundEntry = findObjectPropertyEntry(externalArgs, dataView, entryPointer, p);
if (foundEntry === undefined) {
return undefined;
}
const [valueEntry] = readEntry(externalArgs, dataView, foundEntry[1].value.value);
return entryToFinalJavaScriptValue(externalArgs, dataView, valueEntry, foundEntry[1].value.value);
}

@@ -1,6 +0,5 @@

import { primitiveValueToEntry, isPrimitive } from "./utils";
import { primitiveValueToEntry, isPrimitive, getOurPointerIfApplicable } from "./utils";
import { appendEntry } from "./store";
import { objectSaver } from "./objectSaver";
import { arraySaver } from "./arraySaver";
import { GET_UNDERLYING_POINTER_SYMBOL } from "./symbols";
import { ENTRY_TYPE } from "./entry-types";

@@ -10,2 +9,3 @@ export function saveValue(externalArgs, dataView, value) {

let valuePointer = 0;
let maybeOurPointer;

@@ -20,47 +20,29 @@ if (isPrimitive(value)) {

totalWrittenBytes += length;
} else if (maybeOurPointer = getOurPointerIfApplicable(value, dataView)) {
valuePointer = maybeOurPointer;
totalWrittenBytes += 0;
} else if (Array.isArray(value)) {
const maybeOurPointer = value[GET_UNDERLYING_POINTER_SYMBOL];
if (maybeOurPointer) {
valuePointer = maybeOurPointer;
totalWrittenBytes += 0;
} else {
const {
start,
length
} = arraySaver(externalArgs, dataView, value);
valuePointer = start;
totalWrittenBytes += length;
}
const {
start,
length
} = arraySaver(externalArgs, dataView, value);
valuePointer = start;
totalWrittenBytes += length;
} else if (value instanceof Date) {
const maybeOurPointer = value[GET_UNDERLYING_POINTER_SYMBOL];
if (maybeOurPointer) {
valuePointer = maybeOurPointer;
totalWrittenBytes += 0;
} else {
const {
start,
length
} = appendEntry(externalArgs, dataView, {
type: ENTRY_TYPE.DATE,
value: value.getTime()
});
valuePointer = start;
totalWrittenBytes += length;
}
const {
start,
length
} = appendEntry(externalArgs, dataView, {
type: ENTRY_TYPE.DATE,
value: value.getTime()
});
valuePointer = start;
totalWrittenBytes += length;
} else if (typeof value === "object") {
const maybeOurPointer = value[GET_UNDERLYING_POINTER_SYMBOL];
if (maybeOurPointer) {
valuePointer = maybeOurPointer;
totalWrittenBytes += 0;
} else {
const {
start,
length
} = objectSaver(externalArgs, dataView, value);
valuePointer = start;
totalWrittenBytes += length;
}
const {
start,
length
} = objectSaver(externalArgs, dataView, value);
valuePointer = start;
totalWrittenBytes += length;
} else {

@@ -67,0 +49,0 @@ throw new Error("unsupported yet");

import { ENTRY_TYPE } from "./entry-types";
import { arrayBufferCopyTo, isPrimitive, primitiveValueToEntry } from "./utils";
import { BigInt64OverflowError, OutOfMemoryError } from "./exceptions";
import { FIRST_FREE_BYTE_POINTER_TO_POINTER, INITIAL_ENTRY_POINTER_TO_POINTER, INITIAL_ENTRY_POINTER_VALUE } from "./consts";
const MAX_64_BIG_INT = BigInt("0xFFFFFFFFFFFFFFFF");
export function initializeArrayBuffer(arrayBuffer) {

@@ -8,5 +11,5 @@ const dataView = new DataView(arrayBuffer); // global lock

dataView.setUint32(8, 24); // first entry pointer
dataView.setUint32(FIRST_FREE_BYTE_POINTER_TO_POINTER, INITIAL_ENTRY_POINTER_VALUE); // first entry pointer
dataView.setUint32(16, 24);
dataView.setUint32(INITIAL_ENTRY_POINTER_TO_POINTER, INITIAL_ENTRY_POINTER_VALUE);
return dataView;

@@ -55,12 +58,12 @@ }

case ENTRY_TYPE.BIGINT:
dataView.setBigInt64(cursor, entry.value);
case ENTRY_TYPE.BIGINT_NEGATIVE:
case ENTRY_TYPE.BIGINT_POSITIVE:
if (entry.value > MAX_64_BIG_INT || entry.value < -MAX_64_BIG_INT) {
throw new BigInt64OverflowError();
}
dataView.setBigUint64(cursor, entry.type === ENTRY_TYPE.BIGINT_NEGATIVE ? -entry.value : entry.value);
cursor += BigInt64Array.BYTES_PER_ELEMENT;
break;
case ENTRY_TYPE.UBIGINT:
dataView.setBigUint64(cursor, entry.value);
cursor += BigUint64Array.BYTES_PER_ELEMENT;
break;
case ENTRY_TYPE.OBJECT:

@@ -112,9 +115,18 @@ dataView.setUint32(cursor, entry.value);

// End of data pointer
const firstFreeByte = dataView.getUint32(8);
const written = writeEntry(externalArgs, dataView, firstFreeByte, entry);
dataView.setUint32(8, firstFreeByte + written);
return {
start: firstFreeByte,
length: written
};
const firstFreeByte = dataView.getUint32(FIRST_FREE_BYTE_POINTER_TO_POINTER);
try {
const written = writeEntry(externalArgs, dataView, firstFreeByte, entry);
dataView.setUint32(FIRST_FREE_BYTE_POINTER_TO_POINTER, firstFreeByte + written);
return {
start: firstFreeByte,
length: written
};
} catch (e) {
if (e instanceof RangeError) {
// Assume Offset is outside the bounds of the DataView
// need to test it cross browser
throw new OutOfMemoryError();
} else throw e;
}
}

@@ -152,19 +164,25 @@ export function readEntry(externalArgs, dataView, startingCursor) {

entry.allocatedBytes = dataView.getUint16(cursor);
cursor += Uint16Array.BYTES_PER_ELEMENT; // this wrapping is needed until:
// https://github.com/whatwg/encoding/issues/172
// eslint-disable-next-line no-case-declarations
cursor += Uint16Array.BYTES_PER_ELEMENT; // decode fails with zero length array
const tempAB = new ArrayBuffer(stringLength);
arrayBufferCopyTo(dataView.buffer, cursor, stringLength, tempAB, 0);
entry.value = externalArgs.textDecoder.decode(tempAB);
if (stringLength > 0) {
// this wrapping is needed until:
// https://github.com/whatwg/encoding/issues/172
// eslint-disable-next-line no-case-declarations
const tempAB = new ArrayBuffer(stringLength);
arrayBufferCopyTo(dataView.buffer, cursor, stringLength, tempAB, 0);
entry.value = externalArgs.textDecoder.decode(tempAB);
} else {
entry.value = "";
}
cursor += stringLength;
break;
case ENTRY_TYPE.BIGINT:
entry.value = dataView.getBigInt64(cursor);
cursor += BigInt64Array.BYTES_PER_ELEMENT;
case ENTRY_TYPE.BIGINT_POSITIVE:
entry.value = dataView.getBigUint64(cursor);
cursor += BigUint64Array.BYTES_PER_ELEMENT;
break;
case ENTRY_TYPE.UBIGINT:
entry.value = dataView.getBigUint64(cursor);
case ENTRY_TYPE.BIGINT_NEGATIVE:
entry.value = -dataView.getBigUint64(cursor);
cursor += BigUint64Array.BYTES_PER_ELEMENT;

@@ -218,5 +236,13 @@ break;

export function reserveMemory(dataView, length) {
const firstFreeByte = dataView.getUint32(8);
dataView.setUint32(8, firstFreeByte + length);
return firstFreeByte;
try {
const allocatedMemoryAddress = dataView.getUint32(FIRST_FREE_BYTE_POINTER_TO_POINTER);
dataView.setUint32(FIRST_FREE_BYTE_POINTER_TO_POINTER, allocatedMemoryAddress + length);
return allocatedMemoryAddress;
} catch (e) {
if (e instanceof RangeError) {
// Assume Offset is outside the bounds of the DataView
// need to test it cross browser
throw new OutOfMemoryError();
} else throw e;
}
}

@@ -231,3 +257,3 @@ export function canSaveValueIntoEntry(externalArgs, entryA, value) {

if ((entryA.type === ENTRY_TYPE.BIGINT || entryA.type === ENTRY_TYPE.UBIGINT || entryA.type === ENTRY_TYPE.NUMBER) && (typeofTheValue === "bigint" || typeofTheValue === "number")) {
if ((entryA.type === ENTRY_TYPE.BIGINT_NEGATIVE || entryA.type === ENTRY_TYPE.BIGINT_POSITIVE || entryA.type === ENTRY_TYPE.NUMBER) && (typeofTheValue === "bigint" || typeofTheValue === "number")) {
return true;

@@ -234,0 +260,0 @@ }

export declare const GET_UNDERLYING_ARRAY_BUFFER_SYMBOL: unique symbol;
export declare const GET_UNDERLYING_POINTER_SYMBOL: unique symbol;
export declare const REPLACE_DATA_VIEW_SYMBOL: unique symbol;
export declare const INTERNAL_API_SYMBOL: unique symbol;
//# sourceMappingURL=symbols.d.ts.map
export const GET_UNDERLYING_ARRAY_BUFFER_SYMBOL = Symbol("GET_UNDERLYING_ARRAY_BUFFER_SYMBOL");
export const GET_UNDERLYING_POINTER_SYMBOL = Symbol("GET_UNDERLYING_POINTER_SYMBOL");
export const REPLACE_DATA_VIEW_SYMBOL = Symbol("REPLACE_DATA_VIEW_SYMBOL");
export const REPLACE_DATA_VIEW_SYMBOL = Symbol("REPLACE_DATA_VIEW_SYMBOL");
export const INTERNAL_API_SYMBOL = Symbol("INTERNAL_API");

@@ -0,1 +1,2 @@

import { FIRST_FREE_BYTE_POINTER_TO_POINTER } from "./consts";
export function arrayBuffer2HexArray(buffer, withByteNumber = false) {

@@ -9,3 +10,3 @@ if (withByteNumber) {

export function getFirstFreeByte(arrayBuffer) {
return new DataView(arrayBuffer).getUint32(8);
return new DataView(arrayBuffer).getUint32(FIRST_FREE_BYTE_POINTER_TO_POINTER);
}

@@ -7,3 +7,4 @@ import { primitive, Entry, ExternalArgs } from "./interfaces";

export declare function arrayBufferCopyTo(origin: ArrayBuffer, startByte: number, length: number, target: ArrayBuffer, toTargetByte: number): void;
export declare function getFirstFreeByte(arrayBuffer: ArrayBuffer): number;
export declare function getFirstFreeByte(arrayBufferOrDataView: DataView | ArrayBuffer): number;
export declare function getOurPointerIfApplicable(value: any, ourDateView: DataView): number | undefined;
//# sourceMappingURL=utils.d.ts.map
import { ENTRY_TYPE } from "./entry-types";
import { INTERNAL_API_SYMBOL } from "./symbols";
import { FIRST_FREE_BYTE_POINTER_TO_POINTER } from "./consts";
const primitives = ["string", "number", "bigint", "boolean", "undefined"];

@@ -32,3 +34,3 @@ export function isPrimitive(value) {

return {
type: ENTRY_TYPE.BIGINT,
type: value >= BigInt("0") ? ENTRY_TYPE.BIGINT_POSITIVE : ENTRY_TYPE.BIGINT_NEGATIVE,
value

@@ -77,4 +79,11 @@ };

}
export function getFirstFreeByte(arrayBuffer) {
return new DataView(arrayBuffer).getUint32(8);
export function getFirstFreeByte(arrayBufferOrDataView) {
return (arrayBufferOrDataView instanceof DataView ? arrayBufferOrDataView : new DataView(arrayBufferOrDataView)).getUint32(FIRST_FREE_BYTE_POINTER_TO_POINTER);
}
export function getOurPointerIfApplicable(value, ourDateView) {
const api = value[INTERNAL_API_SYMBOL];
if (api && api.getDataView() === ourDateView) {
return api.getEntryPointer();
}
}

@@ -54,2 +54,9 @@ 'use strict';

const REPLACE_DATA_VIEW_SYMBOL = Symbol("REPLACE_DATA_VIEW_SYMBOL");
const INTERNAL_API_SYMBOL = Symbol("INTERNAL_API");
const FIRST_FREE_BYTE_POINTER_TO_POINTER = 8;
const INITIAL_ENTRY_POINTER_TO_POINTER = 16;
const INITIAL_ENTRY_POINTER_VALUE = 24;
const primitives = ["string", "number", "bigint", "boolean", "undefined"];

@@ -85,3 +92,3 @@ function isPrimitive(value) {

return {
type: ENTRY_TYPE.BIGINT,
type: value >= BigInt("0") ? ENTRY_TYPE.BIGINT_POSITIVE : ENTRY_TYPE.BIGINT_NEGATIVE,
value

@@ -130,6 +137,13 @@ };

}
function getFirstFreeByte(arrayBuffer) {
return new DataView(arrayBuffer).getUint32(8);
function getFirstFreeByte(arrayBufferOrDataView) {
return (arrayBufferOrDataView instanceof DataView ? arrayBufferOrDataView : new DataView(arrayBufferOrDataView)).getUint32(FIRST_FREE_BYTE_POINTER_TO_POINTER);
}
function getOurPointerIfApplicable(value, ourDateView) {
const api = value[INTERNAL_API_SYMBOL];
if (api && api.getDataView() === ourDateView) {
return api.getEntryPointer();
}
}
let ENTRY_TYPE;

@@ -141,4 +155,4 @@

ENTRY_TYPE[ENTRY_TYPE["NUMBER"] = 2] = "NUMBER";
ENTRY_TYPE[ENTRY_TYPE["BIGINT"] = 3] = "BIGINT";
ENTRY_TYPE[ENTRY_TYPE["UBIGINT"] = 4] = "UBIGINT";
ENTRY_TYPE[ENTRY_TYPE["BIGINT_POSITIVE"] = 3] = "BIGINT_POSITIVE";
ENTRY_TYPE[ENTRY_TYPE["BIGINT_NEGATIVE"] = 4] = "BIGINT_NEGATIVE";
ENTRY_TYPE[ENTRY_TYPE["STRING"] = 5] = "STRING";

@@ -155,5 +169,37 @@ ENTRY_TYPE[ENTRY_TYPE["BOOLEAN"] = 6] = "BOOLEAN";

const PRIMITIVE_TYPES = [ENTRY_TYPE.NULL, ENTRY_TYPE.UNDEFINED, ENTRY_TYPE.NUMBER, ENTRY_TYPE.BIGINT, ENTRY_TYPE.UBIGINT, ENTRY_TYPE.BOOLEAN, ENTRY_TYPE.STRING];
const PRIMITIVE_TYPES = [ENTRY_TYPE.NULL, ENTRY_TYPE.UNDEFINED, ENTRY_TYPE.NUMBER, ENTRY_TYPE.BIGINT_POSITIVE, ENTRY_TYPE.BIGINT_NEGATIVE, ENTRY_TYPE.BOOLEAN, ENTRY_TYPE.STRING];
const isPrimitiveEntryType = createKnownTypeGuard(PRIMITIVE_TYPES);
class BigInt64OverflowError extends RangeError {
constructor() {
super("BigInt64OverflowError");
}
}
class IllegalObjectPropConfigError extends RangeError {
constructor() {
super("IllegalObjectPropConfigError");
}
}
class IllegalArrayIndexError extends RangeError {
constructor() {
super("IllegalArrayIndexError");
}
}
class UnsupportedOperationError extends Error {
constructor() {
super("UnsupportedOperationError");
}
}
class OutOfMemoryError extends Error {
constructor() {
super("OutOfMemoryError");
}
}
const MAX_64_BIG_INT = BigInt("0xFFFFFFFFFFFFFFFF");
function initializeArrayBuffer(arrayBuffer) {

@@ -164,5 +210,5 @@ const dataView = new DataView(arrayBuffer); // global lock

dataView.setUint32(8, 24); // first entry pointer
dataView.setUint32(FIRST_FREE_BYTE_POINTER_TO_POINTER, INITIAL_ENTRY_POINTER_VALUE); // first entry pointer
dataView.setUint32(16, 24);
dataView.setUint32(INITIAL_ENTRY_POINTER_TO_POINTER, INITIAL_ENTRY_POINTER_VALUE);
return dataView;

@@ -211,12 +257,12 @@ }

case ENTRY_TYPE.BIGINT:
dataView.setBigInt64(cursor, entry.value);
case ENTRY_TYPE.BIGINT_NEGATIVE:
case ENTRY_TYPE.BIGINT_POSITIVE:
if (entry.value > MAX_64_BIG_INT || entry.value < -MAX_64_BIG_INT) {
throw new BigInt64OverflowError();
}
dataView.setBigUint64(cursor, entry.type === ENTRY_TYPE.BIGINT_NEGATIVE ? -entry.value : entry.value);
cursor += BigInt64Array.BYTES_PER_ELEMENT;
break;
case ENTRY_TYPE.UBIGINT:
dataView.setBigUint64(cursor, entry.value);
cursor += BigUint64Array.BYTES_PER_ELEMENT;
break;
case ENTRY_TYPE.OBJECT:

@@ -268,9 +314,18 @@ dataView.setUint32(cursor, entry.value);

// End of data pointer
const firstFreeByte = dataView.getUint32(8);
const written = writeEntry(externalArgs, dataView, firstFreeByte, entry);
dataView.setUint32(8, firstFreeByte + written);
return {
start: firstFreeByte,
length: written
};
const firstFreeByte = dataView.getUint32(FIRST_FREE_BYTE_POINTER_TO_POINTER);
try {
const written = writeEntry(externalArgs, dataView, firstFreeByte, entry);
dataView.setUint32(FIRST_FREE_BYTE_POINTER_TO_POINTER, firstFreeByte + written);
return {
start: firstFreeByte,
length: written
};
} catch (e) {
if (e instanceof RangeError) {
// Assume Offset is outside the bounds of the DataView
// need to test it cross browser
throw new OutOfMemoryError();
} else throw e;
}
}

@@ -308,19 +363,25 @@ function readEntry(externalArgs, dataView, startingCursor) {

entry.allocatedBytes = dataView.getUint16(cursor);
cursor += Uint16Array.BYTES_PER_ELEMENT; // this wrapping is needed until:
// https://github.com/whatwg/encoding/issues/172
// eslint-disable-next-line no-case-declarations
cursor += Uint16Array.BYTES_PER_ELEMENT; // decode fails with zero length array
const tempAB = new ArrayBuffer(stringLength);
arrayBufferCopyTo(dataView.buffer, cursor, stringLength, tempAB, 0);
entry.value = externalArgs.textDecoder.decode(tempAB);
if (stringLength > 0) {
// this wrapping is needed until:
// https://github.com/whatwg/encoding/issues/172
// eslint-disable-next-line no-case-declarations
const tempAB = new ArrayBuffer(stringLength);
arrayBufferCopyTo(dataView.buffer, cursor, stringLength, tempAB, 0);
entry.value = externalArgs.textDecoder.decode(tempAB);
} else {
entry.value = "";
}
cursor += stringLength;
break;
case ENTRY_TYPE.BIGINT:
entry.value = dataView.getBigInt64(cursor);
cursor += BigInt64Array.BYTES_PER_ELEMENT;
case ENTRY_TYPE.BIGINT_POSITIVE:
entry.value = dataView.getBigUint64(cursor);
cursor += BigUint64Array.BYTES_PER_ELEMENT;
break;
case ENTRY_TYPE.UBIGINT:
entry.value = dataView.getBigUint64(cursor);
case ENTRY_TYPE.BIGINT_NEGATIVE:
entry.value = -dataView.getBigUint64(cursor);
cursor += BigUint64Array.BYTES_PER_ELEMENT;

@@ -374,5 +435,13 @@ break;

function reserveMemory(dataView, length) {
const firstFreeByte = dataView.getUint32(8);
dataView.setUint32(8, firstFreeByte + length);
return firstFreeByte;
try {
const allocatedMemoryAddress = dataView.getUint32(FIRST_FREE_BYTE_POINTER_TO_POINTER);
dataView.setUint32(FIRST_FREE_BYTE_POINTER_TO_POINTER, allocatedMemoryAddress + length);
return allocatedMemoryAddress;
} catch (e) {
if (e instanceof RangeError) {
// Assume Offset is outside the bounds of the DataView
// need to test it cross browser
throw new OutOfMemoryError();
} else throw e;
}
}

@@ -387,3 +456,3 @@ function canSaveValueIntoEntry(externalArgs, entryA, value) {

if ((entryA.type === ENTRY_TYPE.BIGINT || entryA.type === ENTRY_TYPE.UBIGINT || entryA.type === ENTRY_TYPE.NUMBER) && (typeofTheValue === "bigint" || typeofTheValue === "number")) {
if ((entryA.type === ENTRY_TYPE.BIGINT_NEGATIVE || entryA.type === ENTRY_TYPE.BIGINT_POSITIVE || entryA.type === ENTRY_TYPE.NUMBER) && (typeofTheValue === "bigint" || typeofTheValue === "number")) {
return true;

@@ -445,9 +514,6 @@ }

const GET_UNDERLYING_ARRAY_BUFFER_SYMBOL = Symbol("GET_UNDERLYING_ARRAY_BUFFER_SYMBOL");
const GET_UNDERLYING_POINTER_SYMBOL = Symbol("GET_UNDERLYING_POINTER_SYMBOL");
const REPLACE_DATA_VIEW_SYMBOL = Symbol("REPLACE_DATA_VIEW_SYMBOL");
function saveValue(externalArgs, dataView, value) {
let totalWrittenBytes = 0;
let valuePointer = 0;
let maybeOurPointer;

@@ -462,47 +528,29 @@ if (isPrimitive(value)) {

totalWrittenBytes += length;
} else if (maybeOurPointer = getOurPointerIfApplicable(value, dataView)) {
valuePointer = maybeOurPointer;
totalWrittenBytes += 0;
} else if (Array.isArray(value)) {
const maybeOurPointer = value[GET_UNDERLYING_POINTER_SYMBOL];
if (maybeOurPointer) {
valuePointer = maybeOurPointer;
totalWrittenBytes += 0;
} else {
const {
start,
length
} = arraySaver(externalArgs, dataView, value);
valuePointer = start;
totalWrittenBytes += length;
}
const {
start,
length
} = arraySaver(externalArgs, dataView, value);
valuePointer = start;
totalWrittenBytes += length;
} else if (value instanceof Date) {
const maybeOurPointer = value[GET_UNDERLYING_POINTER_SYMBOL];
if (maybeOurPointer) {
valuePointer = maybeOurPointer;
totalWrittenBytes += 0;
} else {
const {
start,
length
} = appendEntry(externalArgs, dataView, {
type: ENTRY_TYPE.DATE,
value: value.getTime()
});
valuePointer = start;
totalWrittenBytes += length;
}
const {
start,
length
} = appendEntry(externalArgs, dataView, {
type: ENTRY_TYPE.DATE,
value: value.getTime()
});
valuePointer = start;
totalWrittenBytes += length;
} else if (typeof value === "object") {
const maybeOurPointer = value[GET_UNDERLYING_POINTER_SYMBOL];
if (maybeOurPointer) {
valuePointer = maybeOurPointer;
totalWrittenBytes += 0;
} else {
const {
start,
length
} = objectSaver(externalArgs, dataView, value);
valuePointer = start;
totalWrittenBytes += length;
}
const {
start,
length
} = objectSaver(externalArgs, dataView, value);
valuePointer = start;
totalWrittenBytes += length;
} else {

@@ -552,119 +600,2 @@ throw new Error("unsupported yet");

function deleteObjectPropertyEntryByKey(externalArgs, dataView, containingObjectEntryPointer, keyToDeleteBy) {
invariant(containingObjectEntryPointer !== 0, "containingObjectEntryPointer Must not be 0");
const objectEntry = readEntry(externalArgs, dataView, containingObjectEntryPointer)[0];
if (objectEntry.value === 0) {
// Nothing to delete here
return false;
}
const firstPropEntry = readEntry(externalArgs, dataView, objectEntry.value)[0];
if (firstPropEntry.value.key === keyToDeleteBy) {
writeEntry(externalArgs, dataView, containingObjectEntryPointer, {
type: ENTRY_TYPE.OBJECT,
value: firstPropEntry.value.next
});
return true;
}
let entryToMaybeUpdate = firstPropEntry;
let entryToMaybeUpdatePointer = firstPropEntry.value.next;
let entryToMaybeDelete;
while (entryToMaybeUpdate.value.next !== 0) {
entryToMaybeDelete = readEntry(externalArgs, dataView, entryToMaybeUpdate.value.next)[0];
if (entryToMaybeDelete.value.key === keyToDeleteBy) {
break;
}
entryToMaybeUpdatePointer = entryToMaybeUpdate.value.next;
entryToMaybeUpdate = entryToMaybeDelete;
}
if (entryToMaybeDelete && entryToMaybeDelete.value.key === keyToDeleteBy) {
writeEntry(externalArgs, dataView, entryToMaybeUpdatePointer, {
type: ENTRY_TYPE.OBJECT_PROP,
value: {
key: entryToMaybeUpdate.value.key,
value: entryToMaybeUpdate.value.value,
next: entryToMaybeDelete.value.next
}
});
return true;
} else {
// key not found
return false;
} // Nothing to delete
}
/**
* If the object has no props, return the object pointer itself
* @param dataView
* @param containingObjectEntryPointer
* @param textDecoder
*/
function findLastObjectPropertyEntry(externalArgs, dataView, containingObjectEntryPointer) {
const [containingObjectEntry] = readEntry(externalArgs, dataView, containingObjectEntryPointer);
if (containingObjectEntry.value === 0) {
return [containingObjectEntryPointer, containingObjectEntry];
}
let nextElementPointer = containingObjectEntry.value; // eslint-disable-next-line no-constant-condition
while (true) {
const [objectPropEntry] = readEntry(externalArgs, dataView, nextElementPointer);
if (objectPropEntry.value.next === 0) {
return [nextElementPointer, objectPropEntry];
}
nextElementPointer = objectPropEntry.value.next;
}
}
function findObjectPropertyEntry(externalArgs, dataView, containingObjectEntryPointer, key) {
const [containingObjectEntry] = readEntry(externalArgs, dataView, containingObjectEntryPointer);
let currentPointer = containingObjectEntry.value;
let objectPropEntry;
if (containingObjectEntry.value === 0) {
return undefined;
} // eslint-disable-next-line no-constant-condition
while (true) {
[objectPropEntry] = readEntry(externalArgs, dataView, currentPointer);
if (objectPropEntry.value.key === key || objectPropEntry.value.next === 0) {
break;
}
currentPointer = objectPropEntry.value.next;
}
if (objectPropEntry.value.key === key) {
return [currentPointer, objectPropEntry];
}
return undefined;
}
function getObjectPropertiesEntries(externalArgs, dataView, containingObjectEntryPointer) {
const [containingObjectEntry] = readEntry(externalArgs, dataView, containingObjectEntryPointer);
const foundProps = [];
let nextElementPointer = containingObjectEntry.value;
let objectPropEntry;
do {
[objectPropEntry] = readEntry(externalArgs, dataView, nextElementPointer);
foundProps.push(objectPropEntry);
nextElementPointer = objectPropEntry.value.next;
} while (nextElementPointer !== 0);
return foundProps;
}
// isolated due to parser changes ts 3.7

@@ -917,2 +848,29 @@ // https://github.com/microsoft/TypeScript/pull/32695

/**
* Catches if the operation inside CB throw OOM exception,
* and if it did, restore the firstFreeByte & set everything to zero.
*
* For cases when we got oom in the middle of saving object, array, etc
*/
function handleOOM(operation, dataView) {
const prevFirstFreeByte = getFirstFreeByte(dataView.buffer);
try {
operation();
} catch (e) {
const currentFirstFreeByte = getFirstFreeByte(dataView.buffer); // restore prev state before the OOM operation
if (prevFirstFreeByte !== currentFirstFreeByte) {
dataView.setUint32(FIRST_FREE_BYTE_POINTER_TO_POINTER, prevFirstFreeByte);
for (let i = prevFirstFreeByte; i <= currentFirstFreeByte; i += 1) {
dataView.setUint8(i, 0);
}
}
throw e;
}
}
class ArrayWrapper {

@@ -926,4 +884,4 @@ constructor(externalArgs, dataViewCarrier, entryPointer) {

get(target, p) {
if (p === GET_UNDERLYING_POINTER_SYMBOL) {
return this.entryPointer;
if (p === INTERNAL_API_SYMBOL) {
return this;
}

@@ -976,2 +934,6 @@

if (!this.has(target, prop)) {
return undefined;
}
return {

@@ -995,4 +957,8 @@ configurable: false,

set(target, p, value) {
if (p === "length") {
set(target, accessedProp, value) {
if (typeof accessedProp === "symbol") {
throw new IllegalArrayIndexError();
}
if (accessedProp === "length") {
if (!Number.isSafeInteger(value) || value < 0) {

@@ -1008,28 +974,26 @@ throw new RangeError("Invalid array length");

if (currentLength > value) {
this.splice(value, currentLength - value);
return true;
}
handleOOM(() => {
if (currentLength > value) {
this.splice(value, currentLength - value);
return true;
}
extendArrayIfNeeded(this.externalArgs, this.dataViewCarrier.dataView, this.entryPointer, value);
extendArrayIfNeeded(this.externalArgs, this.dataViewCarrier.dataView, this.entryPointer, value);
}, this.dataViewCarrier.dataView);
return true;
}
extendArrayIfNeeded(this.externalArgs, this.dataViewCarrier.dataView, this.entryPointer, Number.parseInt(p, 10) + 1);
setValueAtArrayIndex(this.externalArgs, this.dataViewCarrier.dataView, this.entryPointer, Number.parseInt(p, 10), value);
return true;
}
const possibleIndex = Number.parseInt(accessedProp, 10);
isExtensible() {
if (!Number.isSafeInteger(possibleIndex) || possibleIndex < 0) {
throw new IllegalArrayIndexError();
}
handleOOM(() => {
extendArrayIfNeeded(this.externalArgs, this.dataViewCarrier.dataView, this.entryPointer, possibleIndex + 1);
setValueAtArrayIndex(this.externalArgs, this.dataViewCarrier.dataView, this.entryPointer, possibleIndex, value);
}, this.dataViewCarrier.dataView);
return true;
}
preventExtensions() {
throw new Error("unsupported");
}
setPrototypeOf() {
throw new Error("unsupported");
}
*entries() {

@@ -1098,2 +1062,34 @@ let index = 0;

getDataView() {
return this.dataViewCarrier.dataView;
}
getEntryPointer() {
return this.entryPointer;
}
isExtensible() {
return true;
}
preventExtensions() {
throw new UnsupportedOperationError();
}
setPrototypeOf() {
throw new UnsupportedOperationError();
}
defineProperty() {
throw new UnsupportedOperationError(); // if (
// typeof p === "symbol" ||
// attributes.enumerable === false ||
// attributes.get ||
// attributes.set
// ) {
// throw new IllegalObjectPropConfigError();
// }
// return Object.defineProperty(target, p, attributes);
}
}

@@ -1119,2 +1115,6 @@ function createArrayWrapper(externalArgs, dataViewCarrier, entryPointer) {

get(target, p) {
if (p === INTERNAL_API_SYMBOL) {
return this;
}
if (getFunctions.includes(p)) {

@@ -1157,2 +1157,22 @@ if (!(p in this.useMeToGiveNamesToFunctionsAndCacheThem)) {

getDataView() {
return this.dataViewCarrier.dataView;
}
getEntryPointer() {
return this.entryPointer;
}
defineProperty() {
throw new UnsupportedOperationError();
}
setPrototypeOf() {
throw new UnsupportedOperationError();
}
isExtensible() {
return false;
}
}

@@ -1233,2 +1253,179 @@ function createDateWrapper(externalArgs, dataViewCarrier, entryPointer) {

function deleteObjectPropertyEntryByKey(externalArgs, dataView, containingObjectEntryPointer, keyToDeleteBy) {
invariant(containingObjectEntryPointer !== 0, "containingObjectEntryPointer Must not be 0");
const objectEntry = readEntry(externalArgs, dataView, containingObjectEntryPointer)[0];
if (objectEntry.value === 0) {
// Nothing to delete here
return false;
}
const firstPropEntry = readEntry(externalArgs, dataView, objectEntry.value)[0];
if (firstPropEntry.value.key === keyToDeleteBy) {
writeEntry(externalArgs, dataView, containingObjectEntryPointer, {
type: ENTRY_TYPE.OBJECT,
value: firstPropEntry.value.next
});
return true;
}
let entryToMaybeUpdate = firstPropEntry;
let entryToMaybeUpdatePointer = firstPropEntry.value.next;
let entryToMaybeDelete;
while (entryToMaybeUpdate.value.next !== 0) {
entryToMaybeDelete = readEntry(externalArgs, dataView, entryToMaybeUpdate.value.next)[0];
if (entryToMaybeDelete.value.key === keyToDeleteBy) {
break;
}
entryToMaybeUpdatePointer = entryToMaybeUpdate.value.next;
entryToMaybeUpdate = entryToMaybeDelete;
}
if (entryToMaybeDelete && entryToMaybeDelete.value.key === keyToDeleteBy) {
writeEntry(externalArgs, dataView, entryToMaybeUpdatePointer, {
type: ENTRY_TYPE.OBJECT_PROP,
value: {
key: entryToMaybeUpdate.value.key,
value: entryToMaybeUpdate.value.value,
next: entryToMaybeDelete.value.next
}
});
return true;
} else {
// key not found
return false;
} // Nothing to delete
}
/**
* If the object has no props, return the object pointer itself
* @param dataView
* @param containingObjectEntryPointer
* @param textDecoder
*/
function findLastObjectPropertyEntry(externalArgs, dataView, containingObjectEntryPointer) {
const [containingObjectEntry] = readEntry(externalArgs, dataView, containingObjectEntryPointer);
if (containingObjectEntry.value === 0) {
return [containingObjectEntryPointer, containingObjectEntry];
}
let nextElementPointer = containingObjectEntry.value; // eslint-disable-next-line no-constant-condition
while (true) {
const [objectPropEntry] = readEntry(externalArgs, dataView, nextElementPointer);
if (objectPropEntry.value.next === 0) {
return [nextElementPointer, objectPropEntry];
}
nextElementPointer = objectPropEntry.value.next;
}
}
function findObjectPropertyEntry(externalArgs, dataView, containingObjectEntryPointer, key) {
const [containingObjectEntry] = readEntry(externalArgs, dataView, containingObjectEntryPointer);
let currentPointer = containingObjectEntry.value;
let objectPropEntry; // eslint-disable-next-line no-constant-condition
while (currentPointer !== 0) {
[objectPropEntry] = readEntry(externalArgs, dataView, currentPointer);
if (objectPropEntry.value.key === key || objectPropEntry.value.next === 0) {
break;
}
currentPointer = objectPropEntry.value.next;
}
if (objectPropEntry && objectPropEntry.value.key === key) {
return [currentPointer, objectPropEntry];
}
return undefined;
}
function getObjectPropertiesEntries(externalArgs, dataView, containingObjectEntryPointer) {
const [containingObjectEntry] = readEntry(externalArgs, dataView, containingObjectEntryPointer);
const foundProps = [];
let nextElementPointer = containingObjectEntry.value;
let objectPropEntry;
if (nextElementPointer === 0) {
return [];
}
do {
[objectPropEntry] = readEntry(externalArgs, dataView, nextElementPointer);
foundProps.push(objectPropEntry);
nextElementPointer = objectPropEntry.value.next;
} while (nextElementPointer !== 0);
return foundProps;
}
function objectSet(externalArgs, dataView, entryPointer, p, value) {
const foundPropEntry = findObjectPropertyEntry(externalArgs, dataView, entryPointer, p); // new prop
if (foundPropEntry === undefined) {
const {
start: newValueEntryPointer
} = saveValue(externalArgs, dataView, value);
const {
start: newPropEntryPointer
} = appendEntry(externalArgs, dataView, {
type: ENTRY_TYPE.OBJECT_PROP,
value: {
next: 0,
value: newValueEntryPointer,
key: p
}
});
const [lastItemPointer, lastItemEntry] = findLastObjectPropertyEntry(externalArgs, dataView, entryPointer);
if (lastItemEntry.type === ENTRY_TYPE.OBJECT) {
writeEntry(externalArgs, dataView, lastItemPointer, {
type: ENTRY_TYPE.OBJECT,
value: newPropEntryPointer
});
} else {
writeEntry(externalArgs, dataView, lastItemPointer, {
type: ENTRY_TYPE.OBJECT_PROP,
value: {
next: newPropEntryPointer,
value: lastItemEntry.value.value,
key: lastItemEntry.value.key
}
});
}
} else {
if (!overwriteEntryIfPossible(externalArgs, dataView, foundPropEntry[1].value.value, value)) {
const {
start: newValueEntryPointer
} = saveValue(externalArgs, dataView, value); // overwrite value
writeEntry(externalArgs, dataView, foundPropEntry[0], {
type: ENTRY_TYPE.OBJECT_PROP,
value: {
key: foundPropEntry[1].value.key,
next: foundPropEntry[1].value.next,
value: newValueEntryPointer
}
});
}
}
}
function objectGet(externalArgs, dataView, entryPointer, p) {
const foundEntry = findObjectPropertyEntry(externalArgs, dataView, entryPointer, p);
if (foundEntry === undefined) {
return undefined;
}
const [valueEntry] = readEntry(externalArgs, dataView, foundEntry[1].value.value);
return entryToFinalJavaScriptValue(externalArgs, dataView, valueEntry, foundEntry[1].value.value);
}
class ObjectWrapper {

@@ -1246,15 +1443,3 @@ constructor(externalArgs, dataViewCarrier, entryPointer, isTopLevel) {

getUnderlyingArrayBuffer() {
if (!this.isTopLevel) {
throw new Error("Only Supported on Top Level");
}
return this.dataViewCarrier.dataView.buffer;
}
get(target, p) {
if (p === GET_UNDERLYING_ARRAY_BUFFER_SYMBOL) {
return this.getUnderlyingArrayBuffer();
}
if (p === REPLACE_DATA_VIEW_SYMBOL) {

@@ -1264,4 +1449,4 @@ return this.replaceDataView.bind(this);

if (p === GET_UNDERLYING_POINTER_SYMBOL) {
return this.entryPointer;
if (p === INTERNAL_API_SYMBOL) {
return this;
} /// empty object

@@ -1274,13 +1459,3 @@

const foundEntry = findObjectPropertyEntry(this.externalArgs, this.dataViewCarrier.dataView, this.entryPointer, // Add validation ?
// eslint-disable-next-line @typescript-eslint/ban-ts-ignore
// @ts-ignore
p);
if (foundEntry === undefined) {
return undefined;
}
const [valueEntry] = readEntry(this.externalArgs, this.dataViewCarrier.dataView, foundEntry[1].value.value);
return entryToFinalJavaScriptValue(this.externalArgs, this.dataViewCarrier.dataView, valueEntry, foundEntry[1].value.value);
return objectGet(this.externalArgs, this.dataViewCarrier.dataView, this.entryPointer, p);
}

@@ -1302,11 +1477,19 @@

getOwnPropertyDescriptor() {
return {
configurable: true,
enumerable: true
};
getOwnPropertyDescriptor(target, p) {
if (this.has(target, p)) {
return {
configurable: true,
enumerable: true
};
}
return undefined;
}
has(target, p) {
/// empty object
if (typeof p === "symbol") {
throw new IllegalObjectPropConfigError();
} /// empty object
if (this.entry.value === 0) {

@@ -1316,6 +1499,3 @@ return false;

const foundEntry = findObjectPropertyEntry(this.externalArgs, this.dataViewCarrier.dataView, this.entry.value, // Add validation ?
// eslint-disable-next-line @typescript-eslint/ban-ts-ignore
// @ts-ignore
p);
const foundEntry = findObjectPropertyEntry(this.externalArgs, this.dataViewCarrier.dataView, this.entryPointer, p);
return foundEntry !== undefined;

@@ -1325,52 +1505,9 @@ }

set(target, p, value) {
const foundPropEntry = findObjectPropertyEntry(this.externalArgs, this.dataViewCarrier.dataView, this.entryPointer, p); // new prop
if (foundPropEntry === undefined) {
const {
start: newValueEntryPointer
} = saveValue(this.externalArgs, this.dataViewCarrier.dataView, value);
const {
start: newPropEntryPointer
} = appendEntry(this.externalArgs, this.dataViewCarrier.dataView, {
type: ENTRY_TYPE.OBJECT_PROP,
value: {
next: 0,
value: newValueEntryPointer,
key: p
}
});
const [lastItemPointer, lastItemEntry] = findLastObjectPropertyEntry(this.externalArgs, this.dataViewCarrier.dataView, this.entryPointer);
if (lastItemEntry.type === ENTRY_TYPE.OBJECT) {
writeEntry(this.externalArgs, this.dataViewCarrier.dataView, lastItemPointer, {
type: ENTRY_TYPE.OBJECT,
value: newPropEntryPointer
});
} else {
writeEntry(this.externalArgs, this.dataViewCarrier.dataView, lastItemPointer, {
type: ENTRY_TYPE.OBJECT_PROP,
value: {
next: newPropEntryPointer,
value: lastItemEntry.value.value,
key: lastItemEntry.value.key
}
});
}
} else {
if (!overwriteEntryIfPossible(this.externalArgs, this.dataViewCarrier.dataView, foundPropEntry[1].value.value, value)) {
const {
start: newValueEntryPointer
} = saveValue(this.externalArgs, this.dataViewCarrier.dataView, value); // overwrite value
writeEntry(this.externalArgs, this.dataViewCarrier.dataView, foundPropEntry[0], {
type: ENTRY_TYPE.OBJECT_PROP,
value: {
key: foundPropEntry[1].value.key,
next: foundPropEntry[1].value.next,
value: newValueEntryPointer
}
});
}
if (typeof p === "symbol") {
throw new IllegalObjectPropConfigError();
}
handleOOM(() => {
objectSet(this.externalArgs, this.dataViewCarrier.dataView, this.entryPointer, p, value);
}, this.dataViewCarrier.dataView);
return true;

@@ -1384,7 +1521,7 @@ }

preventExtensions() {
throw new Error("unsupported");
throw new UnsupportedOperationError();
}
setPrototypeOf() {
throw new Error("unsupported");
throw new UnsupportedOperationError();
} // getPrototypeOf? (target: T): object | null;

@@ -1399,4 +1536,15 @@ // setPrototypeOf? (target: T, v: any): boolean;

// deleteProperty? (target: T, p: PropertyKey): boolean;
// defineProperty? (target: T, p: PropertyKey, attributes: PropertyDescriptor): boolean;
// enumerate? (target: T): PropertyKey[];
defineProperty() {
throw new UnsupportedOperationError(); // if (
// typeof p === "symbol" ||
// attributes.enumerable === false ||
// attributes.get ||
// attributes.set
// ) {
// throw new IllegalObjectPropConfigError();
// }
// return Object.defineProperty(target, p, attributes);
} // enumerate? (target: T): PropertyKey[];
// ownKeys? (target: T): PropertyKey[];

@@ -1411,2 +1559,10 @@ // apply? (target: T, thisArg: any, argArray?: any): any;

getDataView() {
return this.dataViewCarrier.dataView;
}
getEntryPointer() {
return this.entryPointer;
}
}

@@ -1544,3 +1700,3 @@ function createObjectWrapper(externalArgs, dataViewCarrier, entryPointer, isTopLevel = false) {

} = objectSaver(externalArgsApiToExternalArgsApi(externalArgs), dataView, initialValue);
dataView.setUint32(16, start);
dataView.setUint32(INITIAL_ENTRY_POINTER_TO_POINTER, start);
return createObjectWrapper(externalArgsApiToExternalArgsApi(externalArgs), {

@@ -1565,3 +1721,3 @@ dataView

function getUnderlyingArrayBuffer(objectBuffer) {
return objectBuffer[GET_UNDERLYING_ARRAY_BUFFER_SYMBOL];
return objectBuffer[INTERNAL_API_SYMBOL].getDataView().buffer;
}

@@ -1582,3 +1738,3 @@ /**

dataView
}, dataView.getUint32(16), true);
}, dataView.getUint32(INITIAL_ENTRY_POINTER_TO_POINTER), true);
}

@@ -1585,0 +1741,0 @@ /**

@@ -50,2 +50,9 @@ function _defineProperty(obj, key, value) {

const REPLACE_DATA_VIEW_SYMBOL = Symbol("REPLACE_DATA_VIEW_SYMBOL");
const INTERNAL_API_SYMBOL = Symbol("INTERNAL_API");
const FIRST_FREE_BYTE_POINTER_TO_POINTER = 8;
const INITIAL_ENTRY_POINTER_TO_POINTER = 16;
const INITIAL_ENTRY_POINTER_VALUE = 24;
const primitives = ["string", "number", "bigint", "boolean", "undefined"];

@@ -81,3 +88,3 @@ function isPrimitive(value) {

return {
type: ENTRY_TYPE.BIGINT,
type: value >= BigInt("0") ? ENTRY_TYPE.BIGINT_POSITIVE : ENTRY_TYPE.BIGINT_NEGATIVE,
value

@@ -126,6 +133,13 @@ };

}
function getFirstFreeByte(arrayBuffer) {
return new DataView(arrayBuffer).getUint32(8);
function getFirstFreeByte(arrayBufferOrDataView) {
return (arrayBufferOrDataView instanceof DataView ? arrayBufferOrDataView : new DataView(arrayBufferOrDataView)).getUint32(FIRST_FREE_BYTE_POINTER_TO_POINTER);
}
function getOurPointerIfApplicable(value, ourDateView) {
const api = value[INTERNAL_API_SYMBOL];
if (api && api.getDataView() === ourDateView) {
return api.getEntryPointer();
}
}
let ENTRY_TYPE;

@@ -137,4 +151,4 @@

ENTRY_TYPE[ENTRY_TYPE["NUMBER"] = 2] = "NUMBER";
ENTRY_TYPE[ENTRY_TYPE["BIGINT"] = 3] = "BIGINT";
ENTRY_TYPE[ENTRY_TYPE["UBIGINT"] = 4] = "UBIGINT";
ENTRY_TYPE[ENTRY_TYPE["BIGINT_POSITIVE"] = 3] = "BIGINT_POSITIVE";
ENTRY_TYPE[ENTRY_TYPE["BIGINT_NEGATIVE"] = 4] = "BIGINT_NEGATIVE";
ENTRY_TYPE[ENTRY_TYPE["STRING"] = 5] = "STRING";

@@ -151,5 +165,37 @@ ENTRY_TYPE[ENTRY_TYPE["BOOLEAN"] = 6] = "BOOLEAN";

const PRIMITIVE_TYPES = [ENTRY_TYPE.NULL, ENTRY_TYPE.UNDEFINED, ENTRY_TYPE.NUMBER, ENTRY_TYPE.BIGINT, ENTRY_TYPE.UBIGINT, ENTRY_TYPE.BOOLEAN, ENTRY_TYPE.STRING];
const PRIMITIVE_TYPES = [ENTRY_TYPE.NULL, ENTRY_TYPE.UNDEFINED, ENTRY_TYPE.NUMBER, ENTRY_TYPE.BIGINT_POSITIVE, ENTRY_TYPE.BIGINT_NEGATIVE, ENTRY_TYPE.BOOLEAN, ENTRY_TYPE.STRING];
const isPrimitiveEntryType = createKnownTypeGuard(PRIMITIVE_TYPES);
class BigInt64OverflowError extends RangeError {
constructor() {
super("BigInt64OverflowError");
}
}
class IllegalObjectPropConfigError extends RangeError {
constructor() {
super("IllegalObjectPropConfigError");
}
}
class IllegalArrayIndexError extends RangeError {
constructor() {
super("IllegalArrayIndexError");
}
}
class UnsupportedOperationError extends Error {
constructor() {
super("UnsupportedOperationError");
}
}
class OutOfMemoryError extends Error {
constructor() {
super("OutOfMemoryError");
}
}
const MAX_64_BIG_INT = BigInt("0xFFFFFFFFFFFFFFFF");
function initializeArrayBuffer(arrayBuffer) {

@@ -160,5 +206,5 @@ const dataView = new DataView(arrayBuffer); // global lock

dataView.setUint32(8, 24); // first entry pointer
dataView.setUint32(FIRST_FREE_BYTE_POINTER_TO_POINTER, INITIAL_ENTRY_POINTER_VALUE); // first entry pointer
dataView.setUint32(16, 24);
dataView.setUint32(INITIAL_ENTRY_POINTER_TO_POINTER, INITIAL_ENTRY_POINTER_VALUE);
return dataView;

@@ -207,12 +253,12 @@ }

case ENTRY_TYPE.BIGINT:
dataView.setBigInt64(cursor, entry.value);
case ENTRY_TYPE.BIGINT_NEGATIVE:
case ENTRY_TYPE.BIGINT_POSITIVE:
if (entry.value > MAX_64_BIG_INT || entry.value < -MAX_64_BIG_INT) {
throw new BigInt64OverflowError();
}
dataView.setBigUint64(cursor, entry.type === ENTRY_TYPE.BIGINT_NEGATIVE ? -entry.value : entry.value);
cursor += BigInt64Array.BYTES_PER_ELEMENT;
break;
case ENTRY_TYPE.UBIGINT:
dataView.setBigUint64(cursor, entry.value);
cursor += BigUint64Array.BYTES_PER_ELEMENT;
break;
case ENTRY_TYPE.OBJECT:

@@ -264,9 +310,18 @@ dataView.setUint32(cursor, entry.value);

// End of data pointer
const firstFreeByte = dataView.getUint32(8);
const written = writeEntry(externalArgs, dataView, firstFreeByte, entry);
dataView.setUint32(8, firstFreeByte + written);
return {
start: firstFreeByte,
length: written
};
const firstFreeByte = dataView.getUint32(FIRST_FREE_BYTE_POINTER_TO_POINTER);
try {
const written = writeEntry(externalArgs, dataView, firstFreeByte, entry);
dataView.setUint32(FIRST_FREE_BYTE_POINTER_TO_POINTER, firstFreeByte + written);
return {
start: firstFreeByte,
length: written
};
} catch (e) {
if (e instanceof RangeError) {
// Assume Offset is outside the bounds of the DataView
// need to test it cross browser
throw new OutOfMemoryError();
} else throw e;
}
}

@@ -304,19 +359,25 @@ function readEntry(externalArgs, dataView, startingCursor) {

entry.allocatedBytes = dataView.getUint16(cursor);
cursor += Uint16Array.BYTES_PER_ELEMENT; // this wrapping is needed until:
// https://github.com/whatwg/encoding/issues/172
// eslint-disable-next-line no-case-declarations
cursor += Uint16Array.BYTES_PER_ELEMENT; // decode fails with zero length array
const tempAB = new ArrayBuffer(stringLength);
arrayBufferCopyTo(dataView.buffer, cursor, stringLength, tempAB, 0);
entry.value = externalArgs.textDecoder.decode(tempAB);
if (stringLength > 0) {
// this wrapping is needed until:
// https://github.com/whatwg/encoding/issues/172
// eslint-disable-next-line no-case-declarations
const tempAB = new ArrayBuffer(stringLength);
arrayBufferCopyTo(dataView.buffer, cursor, stringLength, tempAB, 0);
entry.value = externalArgs.textDecoder.decode(tempAB);
} else {
entry.value = "";
}
cursor += stringLength;
break;
case ENTRY_TYPE.BIGINT:
entry.value = dataView.getBigInt64(cursor);
cursor += BigInt64Array.BYTES_PER_ELEMENT;
case ENTRY_TYPE.BIGINT_POSITIVE:
entry.value = dataView.getBigUint64(cursor);
cursor += BigUint64Array.BYTES_PER_ELEMENT;
break;
case ENTRY_TYPE.UBIGINT:
entry.value = dataView.getBigUint64(cursor);
case ENTRY_TYPE.BIGINT_NEGATIVE:
entry.value = -dataView.getBigUint64(cursor);
cursor += BigUint64Array.BYTES_PER_ELEMENT;

@@ -370,5 +431,13 @@ break;

function reserveMemory(dataView, length) {
const firstFreeByte = dataView.getUint32(8);
dataView.setUint32(8, firstFreeByte + length);
return firstFreeByte;
try {
const allocatedMemoryAddress = dataView.getUint32(FIRST_FREE_BYTE_POINTER_TO_POINTER);
dataView.setUint32(FIRST_FREE_BYTE_POINTER_TO_POINTER, allocatedMemoryAddress + length);
return allocatedMemoryAddress;
} catch (e) {
if (e instanceof RangeError) {
// Assume Offset is outside the bounds of the DataView
// need to test it cross browser
throw new OutOfMemoryError();
} else throw e;
}
}

@@ -383,3 +452,3 @@ function canSaveValueIntoEntry(externalArgs, entryA, value) {

if ((entryA.type === ENTRY_TYPE.BIGINT || entryA.type === ENTRY_TYPE.UBIGINT || entryA.type === ENTRY_TYPE.NUMBER) && (typeofTheValue === "bigint" || typeofTheValue === "number")) {
if ((entryA.type === ENTRY_TYPE.BIGINT_NEGATIVE || entryA.type === ENTRY_TYPE.BIGINT_POSITIVE || entryA.type === ENTRY_TYPE.NUMBER) && (typeofTheValue === "bigint" || typeofTheValue === "number")) {
return true;

@@ -441,9 +510,6 @@ }

const GET_UNDERLYING_ARRAY_BUFFER_SYMBOL = Symbol("GET_UNDERLYING_ARRAY_BUFFER_SYMBOL");
const GET_UNDERLYING_POINTER_SYMBOL = Symbol("GET_UNDERLYING_POINTER_SYMBOL");
const REPLACE_DATA_VIEW_SYMBOL = Symbol("REPLACE_DATA_VIEW_SYMBOL");
function saveValue(externalArgs, dataView, value) {
let totalWrittenBytes = 0;
let valuePointer = 0;
let maybeOurPointer;

@@ -458,47 +524,29 @@ if (isPrimitive(value)) {

totalWrittenBytes += length;
} else if (maybeOurPointer = getOurPointerIfApplicable(value, dataView)) {
valuePointer = maybeOurPointer;
totalWrittenBytes += 0;
} else if (Array.isArray(value)) {
const maybeOurPointer = value[GET_UNDERLYING_POINTER_SYMBOL];
if (maybeOurPointer) {
valuePointer = maybeOurPointer;
totalWrittenBytes += 0;
} else {
const {
start,
length
} = arraySaver(externalArgs, dataView, value);
valuePointer = start;
totalWrittenBytes += length;
}
const {
start,
length
} = arraySaver(externalArgs, dataView, value);
valuePointer = start;
totalWrittenBytes += length;
} else if (value instanceof Date) {
const maybeOurPointer = value[GET_UNDERLYING_POINTER_SYMBOL];
if (maybeOurPointer) {
valuePointer = maybeOurPointer;
totalWrittenBytes += 0;
} else {
const {
start,
length
} = appendEntry(externalArgs, dataView, {
type: ENTRY_TYPE.DATE,
value: value.getTime()
});
valuePointer = start;
totalWrittenBytes += length;
}
const {
start,
length
} = appendEntry(externalArgs, dataView, {
type: ENTRY_TYPE.DATE,
value: value.getTime()
});
valuePointer = start;
totalWrittenBytes += length;
} else if (typeof value === "object") {
const maybeOurPointer = value[GET_UNDERLYING_POINTER_SYMBOL];
if (maybeOurPointer) {
valuePointer = maybeOurPointer;
totalWrittenBytes += 0;
} else {
const {
start,
length
} = objectSaver(externalArgs, dataView, value);
valuePointer = start;
totalWrittenBytes += length;
}
const {
start,
length
} = objectSaver(externalArgs, dataView, value);
valuePointer = start;
totalWrittenBytes += length;
} else {

@@ -548,119 +596,2 @@ throw new Error("unsupported yet");

function deleteObjectPropertyEntryByKey(externalArgs, dataView, containingObjectEntryPointer, keyToDeleteBy) {
invariant(containingObjectEntryPointer !== 0, "containingObjectEntryPointer Must not be 0");
const objectEntry = readEntry(externalArgs, dataView, containingObjectEntryPointer)[0];
if (objectEntry.value === 0) {
// Nothing to delete here
return false;
}
const firstPropEntry = readEntry(externalArgs, dataView, objectEntry.value)[0];
if (firstPropEntry.value.key === keyToDeleteBy) {
writeEntry(externalArgs, dataView, containingObjectEntryPointer, {
type: ENTRY_TYPE.OBJECT,
value: firstPropEntry.value.next
});
return true;
}
let entryToMaybeUpdate = firstPropEntry;
let entryToMaybeUpdatePointer = firstPropEntry.value.next;
let entryToMaybeDelete;
while (entryToMaybeUpdate.value.next !== 0) {
entryToMaybeDelete = readEntry(externalArgs, dataView, entryToMaybeUpdate.value.next)[0];
if (entryToMaybeDelete.value.key === keyToDeleteBy) {
break;
}
entryToMaybeUpdatePointer = entryToMaybeUpdate.value.next;
entryToMaybeUpdate = entryToMaybeDelete;
}
if (entryToMaybeDelete && entryToMaybeDelete.value.key === keyToDeleteBy) {
writeEntry(externalArgs, dataView, entryToMaybeUpdatePointer, {
type: ENTRY_TYPE.OBJECT_PROP,
value: {
key: entryToMaybeUpdate.value.key,
value: entryToMaybeUpdate.value.value,
next: entryToMaybeDelete.value.next
}
});
return true;
} else {
// key not found
return false;
} // Nothing to delete
}
/**
* If the object has no props, return the object pointer itself
* @param dataView
* @param containingObjectEntryPointer
* @param textDecoder
*/
function findLastObjectPropertyEntry(externalArgs, dataView, containingObjectEntryPointer) {
const [containingObjectEntry] = readEntry(externalArgs, dataView, containingObjectEntryPointer);
if (containingObjectEntry.value === 0) {
return [containingObjectEntryPointer, containingObjectEntry];
}
let nextElementPointer = containingObjectEntry.value; // eslint-disable-next-line no-constant-condition
while (true) {
const [objectPropEntry] = readEntry(externalArgs, dataView, nextElementPointer);
if (objectPropEntry.value.next === 0) {
return [nextElementPointer, objectPropEntry];
}
nextElementPointer = objectPropEntry.value.next;
}
}
function findObjectPropertyEntry(externalArgs, dataView, containingObjectEntryPointer, key) {
const [containingObjectEntry] = readEntry(externalArgs, dataView, containingObjectEntryPointer);
let currentPointer = containingObjectEntry.value;
let objectPropEntry;
if (containingObjectEntry.value === 0) {
return undefined;
} // eslint-disable-next-line no-constant-condition
while (true) {
[objectPropEntry] = readEntry(externalArgs, dataView, currentPointer);
if (objectPropEntry.value.key === key || objectPropEntry.value.next === 0) {
break;
}
currentPointer = objectPropEntry.value.next;
}
if (objectPropEntry.value.key === key) {
return [currentPointer, objectPropEntry];
}
return undefined;
}
function getObjectPropertiesEntries(externalArgs, dataView, containingObjectEntryPointer) {
const [containingObjectEntry] = readEntry(externalArgs, dataView, containingObjectEntryPointer);
const foundProps = [];
let nextElementPointer = containingObjectEntry.value;
let objectPropEntry;
do {
[objectPropEntry] = readEntry(externalArgs, dataView, nextElementPointer);
foundProps.push(objectPropEntry);
nextElementPointer = objectPropEntry.value.next;
} while (nextElementPointer !== 0);
return foundProps;
}
// isolated due to parser changes ts 3.7

@@ -913,2 +844,29 @@ // https://github.com/microsoft/TypeScript/pull/32695

/**
* Catches if the operation inside CB throw OOM exception,
* and if it did, restore the firstFreeByte & set everything to zero.
*
* For cases when we got oom in the middle of saving object, array, etc
*/
function handleOOM(operation, dataView) {
const prevFirstFreeByte = getFirstFreeByte(dataView.buffer);
try {
operation();
} catch (e) {
const currentFirstFreeByte = getFirstFreeByte(dataView.buffer); // restore prev state before the OOM operation
if (prevFirstFreeByte !== currentFirstFreeByte) {
dataView.setUint32(FIRST_FREE_BYTE_POINTER_TO_POINTER, prevFirstFreeByte);
for (let i = prevFirstFreeByte; i <= currentFirstFreeByte; i += 1) {
dataView.setUint8(i, 0);
}
}
throw e;
}
}
class ArrayWrapper {

@@ -922,4 +880,4 @@ constructor(externalArgs, dataViewCarrier, entryPointer) {

get(target, p) {
if (p === GET_UNDERLYING_POINTER_SYMBOL) {
return this.entryPointer;
if (p === INTERNAL_API_SYMBOL) {
return this;
}

@@ -972,2 +930,6 @@

if (!this.has(target, prop)) {
return undefined;
}
return {

@@ -991,4 +953,8 @@ configurable: false,

set(target, p, value) {
if (p === "length") {
set(target, accessedProp, value) {
if (typeof accessedProp === "symbol") {
throw new IllegalArrayIndexError();
}
if (accessedProp === "length") {
if (!Number.isSafeInteger(value) || value < 0) {

@@ -1004,28 +970,26 @@ throw new RangeError("Invalid array length");

if (currentLength > value) {
this.splice(value, currentLength - value);
return true;
}
handleOOM(() => {
if (currentLength > value) {
this.splice(value, currentLength - value);
return true;
}
extendArrayIfNeeded(this.externalArgs, this.dataViewCarrier.dataView, this.entryPointer, value);
extendArrayIfNeeded(this.externalArgs, this.dataViewCarrier.dataView, this.entryPointer, value);
}, this.dataViewCarrier.dataView);
return true;
}
extendArrayIfNeeded(this.externalArgs, this.dataViewCarrier.dataView, this.entryPointer, Number.parseInt(p, 10) + 1);
setValueAtArrayIndex(this.externalArgs, this.dataViewCarrier.dataView, this.entryPointer, Number.parseInt(p, 10), value);
return true;
}
const possibleIndex = Number.parseInt(accessedProp, 10);
isExtensible() {
if (!Number.isSafeInteger(possibleIndex) || possibleIndex < 0) {
throw new IllegalArrayIndexError();
}
handleOOM(() => {
extendArrayIfNeeded(this.externalArgs, this.dataViewCarrier.dataView, this.entryPointer, possibleIndex + 1);
setValueAtArrayIndex(this.externalArgs, this.dataViewCarrier.dataView, this.entryPointer, possibleIndex, value);
}, this.dataViewCarrier.dataView);
return true;
}
preventExtensions() {
throw new Error("unsupported");
}
setPrototypeOf() {
throw new Error("unsupported");
}
*entries() {

@@ -1094,2 +1058,34 @@ let index = 0;

getDataView() {
return this.dataViewCarrier.dataView;
}
getEntryPointer() {
return this.entryPointer;
}
isExtensible() {
return true;
}
preventExtensions() {
throw new UnsupportedOperationError();
}
setPrototypeOf() {
throw new UnsupportedOperationError();
}
defineProperty() {
throw new UnsupportedOperationError(); // if (
// typeof p === "symbol" ||
// attributes.enumerable === false ||
// attributes.get ||
// attributes.set
// ) {
// throw new IllegalObjectPropConfigError();
// }
// return Object.defineProperty(target, p, attributes);
}
}

@@ -1115,2 +1111,6 @@ function createArrayWrapper(externalArgs, dataViewCarrier, entryPointer) {

get(target, p) {
if (p === INTERNAL_API_SYMBOL) {
return this;
}
if (getFunctions.includes(p)) {

@@ -1153,2 +1153,22 @@ if (!(p in this.useMeToGiveNamesToFunctionsAndCacheThem)) {

getDataView() {
return this.dataViewCarrier.dataView;
}
getEntryPointer() {
return this.entryPointer;
}
defineProperty() {
throw new UnsupportedOperationError();
}
setPrototypeOf() {
throw new UnsupportedOperationError();
}
isExtensible() {
return false;
}
}

@@ -1229,2 +1249,179 @@ function createDateWrapper(externalArgs, dataViewCarrier, entryPointer) {

function deleteObjectPropertyEntryByKey(externalArgs, dataView, containingObjectEntryPointer, keyToDeleteBy) {
invariant(containingObjectEntryPointer !== 0, "containingObjectEntryPointer Must not be 0");
const objectEntry = readEntry(externalArgs, dataView, containingObjectEntryPointer)[0];
if (objectEntry.value === 0) {
// Nothing to delete here
return false;
}
const firstPropEntry = readEntry(externalArgs, dataView, objectEntry.value)[0];
if (firstPropEntry.value.key === keyToDeleteBy) {
writeEntry(externalArgs, dataView, containingObjectEntryPointer, {
type: ENTRY_TYPE.OBJECT,
value: firstPropEntry.value.next
});
return true;
}
let entryToMaybeUpdate = firstPropEntry;
let entryToMaybeUpdatePointer = firstPropEntry.value.next;
let entryToMaybeDelete;
while (entryToMaybeUpdate.value.next !== 0) {
entryToMaybeDelete = readEntry(externalArgs, dataView, entryToMaybeUpdate.value.next)[0];
if (entryToMaybeDelete.value.key === keyToDeleteBy) {
break;
}
entryToMaybeUpdatePointer = entryToMaybeUpdate.value.next;
entryToMaybeUpdate = entryToMaybeDelete;
}
if (entryToMaybeDelete && entryToMaybeDelete.value.key === keyToDeleteBy) {
writeEntry(externalArgs, dataView, entryToMaybeUpdatePointer, {
type: ENTRY_TYPE.OBJECT_PROP,
value: {
key: entryToMaybeUpdate.value.key,
value: entryToMaybeUpdate.value.value,
next: entryToMaybeDelete.value.next
}
});
return true;
} else {
// key not found
return false;
} // Nothing to delete
}
/**
* If the object has no props, return the object pointer itself
* @param dataView
* @param containingObjectEntryPointer
* @param textDecoder
*/
function findLastObjectPropertyEntry(externalArgs, dataView, containingObjectEntryPointer) {
const [containingObjectEntry] = readEntry(externalArgs, dataView, containingObjectEntryPointer);
if (containingObjectEntry.value === 0) {
return [containingObjectEntryPointer, containingObjectEntry];
}
let nextElementPointer = containingObjectEntry.value; // eslint-disable-next-line no-constant-condition
while (true) {
const [objectPropEntry] = readEntry(externalArgs, dataView, nextElementPointer);
if (objectPropEntry.value.next === 0) {
return [nextElementPointer, objectPropEntry];
}
nextElementPointer = objectPropEntry.value.next;
}
}
function findObjectPropertyEntry(externalArgs, dataView, containingObjectEntryPointer, key) {
const [containingObjectEntry] = readEntry(externalArgs, dataView, containingObjectEntryPointer);
let currentPointer = containingObjectEntry.value;
let objectPropEntry; // eslint-disable-next-line no-constant-condition
while (currentPointer !== 0) {
[objectPropEntry] = readEntry(externalArgs, dataView, currentPointer);
if (objectPropEntry.value.key === key || objectPropEntry.value.next === 0) {
break;
}
currentPointer = objectPropEntry.value.next;
}
if (objectPropEntry && objectPropEntry.value.key === key) {
return [currentPointer, objectPropEntry];
}
return undefined;
}
function getObjectPropertiesEntries(externalArgs, dataView, containingObjectEntryPointer) {
const [containingObjectEntry] = readEntry(externalArgs, dataView, containingObjectEntryPointer);
const foundProps = [];
let nextElementPointer = containingObjectEntry.value;
let objectPropEntry;
if (nextElementPointer === 0) {
return [];
}
do {
[objectPropEntry] = readEntry(externalArgs, dataView, nextElementPointer);
foundProps.push(objectPropEntry);
nextElementPointer = objectPropEntry.value.next;
} while (nextElementPointer !== 0);
return foundProps;
}
function objectSet(externalArgs, dataView, entryPointer, p, value) {
const foundPropEntry = findObjectPropertyEntry(externalArgs, dataView, entryPointer, p); // new prop
if (foundPropEntry === undefined) {
const {
start: newValueEntryPointer
} = saveValue(externalArgs, dataView, value);
const {
start: newPropEntryPointer
} = appendEntry(externalArgs, dataView, {
type: ENTRY_TYPE.OBJECT_PROP,
value: {
next: 0,
value: newValueEntryPointer,
key: p
}
});
const [lastItemPointer, lastItemEntry] = findLastObjectPropertyEntry(externalArgs, dataView, entryPointer);
if (lastItemEntry.type === ENTRY_TYPE.OBJECT) {
writeEntry(externalArgs, dataView, lastItemPointer, {
type: ENTRY_TYPE.OBJECT,
value: newPropEntryPointer
});
} else {
writeEntry(externalArgs, dataView, lastItemPointer, {
type: ENTRY_TYPE.OBJECT_PROP,
value: {
next: newPropEntryPointer,
value: lastItemEntry.value.value,
key: lastItemEntry.value.key
}
});
}
} else {
if (!overwriteEntryIfPossible(externalArgs, dataView, foundPropEntry[1].value.value, value)) {
const {
start: newValueEntryPointer
} = saveValue(externalArgs, dataView, value); // overwrite value
writeEntry(externalArgs, dataView, foundPropEntry[0], {
type: ENTRY_TYPE.OBJECT_PROP,
value: {
key: foundPropEntry[1].value.key,
next: foundPropEntry[1].value.next,
value: newValueEntryPointer
}
});
}
}
}
function objectGet(externalArgs, dataView, entryPointer, p) {
const foundEntry = findObjectPropertyEntry(externalArgs, dataView, entryPointer, p);
if (foundEntry === undefined) {
return undefined;
}
const [valueEntry] = readEntry(externalArgs, dataView, foundEntry[1].value.value);
return entryToFinalJavaScriptValue(externalArgs, dataView, valueEntry, foundEntry[1].value.value);
}
class ObjectWrapper {

@@ -1242,15 +1439,3 @@ constructor(externalArgs, dataViewCarrier, entryPointer, isTopLevel) {

getUnderlyingArrayBuffer() {
if (!this.isTopLevel) {
throw new Error("Only Supported on Top Level");
}
return this.dataViewCarrier.dataView.buffer;
}
get(target, p) {
if (p === GET_UNDERLYING_ARRAY_BUFFER_SYMBOL) {
return this.getUnderlyingArrayBuffer();
}
if (p === REPLACE_DATA_VIEW_SYMBOL) {

@@ -1260,4 +1445,4 @@ return this.replaceDataView.bind(this);

if (p === GET_UNDERLYING_POINTER_SYMBOL) {
return this.entryPointer;
if (p === INTERNAL_API_SYMBOL) {
return this;
} /// empty object

@@ -1270,13 +1455,3 @@

const foundEntry = findObjectPropertyEntry(this.externalArgs, this.dataViewCarrier.dataView, this.entryPointer, // Add validation ?
// eslint-disable-next-line @typescript-eslint/ban-ts-ignore
// @ts-ignore
p);
if (foundEntry === undefined) {
return undefined;
}
const [valueEntry] = readEntry(this.externalArgs, this.dataViewCarrier.dataView, foundEntry[1].value.value);
return entryToFinalJavaScriptValue(this.externalArgs, this.dataViewCarrier.dataView, valueEntry, foundEntry[1].value.value);
return objectGet(this.externalArgs, this.dataViewCarrier.dataView, this.entryPointer, p);
}

@@ -1298,11 +1473,19 @@

getOwnPropertyDescriptor() {
return {
configurable: true,
enumerable: true
};
getOwnPropertyDescriptor(target, p) {
if (this.has(target, p)) {
return {
configurable: true,
enumerable: true
};
}
return undefined;
}
has(target, p) {
/// empty object
if (typeof p === "symbol") {
throw new IllegalObjectPropConfigError();
} /// empty object
if (this.entry.value === 0) {

@@ -1312,6 +1495,3 @@ return false;

const foundEntry = findObjectPropertyEntry(this.externalArgs, this.dataViewCarrier.dataView, this.entry.value, // Add validation ?
// eslint-disable-next-line @typescript-eslint/ban-ts-ignore
// @ts-ignore
p);
const foundEntry = findObjectPropertyEntry(this.externalArgs, this.dataViewCarrier.dataView, this.entryPointer, p);
return foundEntry !== undefined;

@@ -1321,52 +1501,9 @@ }

set(target, p, value) {
const foundPropEntry = findObjectPropertyEntry(this.externalArgs, this.dataViewCarrier.dataView, this.entryPointer, p); // new prop
if (foundPropEntry === undefined) {
const {
start: newValueEntryPointer
} = saveValue(this.externalArgs, this.dataViewCarrier.dataView, value);
const {
start: newPropEntryPointer
} = appendEntry(this.externalArgs, this.dataViewCarrier.dataView, {
type: ENTRY_TYPE.OBJECT_PROP,
value: {
next: 0,
value: newValueEntryPointer,
key: p
}
});
const [lastItemPointer, lastItemEntry] = findLastObjectPropertyEntry(this.externalArgs, this.dataViewCarrier.dataView, this.entryPointer);
if (lastItemEntry.type === ENTRY_TYPE.OBJECT) {
writeEntry(this.externalArgs, this.dataViewCarrier.dataView, lastItemPointer, {
type: ENTRY_TYPE.OBJECT,
value: newPropEntryPointer
});
} else {
writeEntry(this.externalArgs, this.dataViewCarrier.dataView, lastItemPointer, {
type: ENTRY_TYPE.OBJECT_PROP,
value: {
next: newPropEntryPointer,
value: lastItemEntry.value.value,
key: lastItemEntry.value.key
}
});
}
} else {
if (!overwriteEntryIfPossible(this.externalArgs, this.dataViewCarrier.dataView, foundPropEntry[1].value.value, value)) {
const {
start: newValueEntryPointer
} = saveValue(this.externalArgs, this.dataViewCarrier.dataView, value); // overwrite value
writeEntry(this.externalArgs, this.dataViewCarrier.dataView, foundPropEntry[0], {
type: ENTRY_TYPE.OBJECT_PROP,
value: {
key: foundPropEntry[1].value.key,
next: foundPropEntry[1].value.next,
value: newValueEntryPointer
}
});
}
if (typeof p === "symbol") {
throw new IllegalObjectPropConfigError();
}
handleOOM(() => {
objectSet(this.externalArgs, this.dataViewCarrier.dataView, this.entryPointer, p, value);
}, this.dataViewCarrier.dataView);
return true;

@@ -1380,7 +1517,7 @@ }

preventExtensions() {
throw new Error("unsupported");
throw new UnsupportedOperationError();
}
setPrototypeOf() {
throw new Error("unsupported");
throw new UnsupportedOperationError();
} // getPrototypeOf? (target: T): object | null;

@@ -1395,4 +1532,15 @@ // setPrototypeOf? (target: T, v: any): boolean;

// deleteProperty? (target: T, p: PropertyKey): boolean;
// defineProperty? (target: T, p: PropertyKey, attributes: PropertyDescriptor): boolean;
// enumerate? (target: T): PropertyKey[];
defineProperty() {
throw new UnsupportedOperationError(); // if (
// typeof p === "symbol" ||
// attributes.enumerable === false ||
// attributes.get ||
// attributes.set
// ) {
// throw new IllegalObjectPropConfigError();
// }
// return Object.defineProperty(target, p, attributes);
} // enumerate? (target: T): PropertyKey[];
// ownKeys? (target: T): PropertyKey[];

@@ -1407,2 +1555,10 @@ // apply? (target: T, thisArg: any, argArray?: any): any;

getDataView() {
return this.dataViewCarrier.dataView;
}
getEntryPointer() {
return this.entryPointer;
}
}

@@ -1540,3 +1696,3 @@ function createObjectWrapper(externalArgs, dataViewCarrier, entryPointer, isTopLevel = false) {

} = objectSaver(externalArgsApiToExternalArgsApi(externalArgs), dataView, initialValue);
dataView.setUint32(16, start);
dataView.setUint32(INITIAL_ENTRY_POINTER_TO_POINTER, start);
return createObjectWrapper(externalArgsApiToExternalArgsApi(externalArgs), {

@@ -1561,3 +1717,3 @@ dataView

function getUnderlyingArrayBuffer(objectBuffer) {
return objectBuffer[GET_UNDERLYING_ARRAY_BUFFER_SYMBOL];
return objectBuffer[INTERNAL_API_SYMBOL].getDataView().buffer;
}

@@ -1578,3 +1734,3 @@ /**

dataView
}, dataView.getUint32(16), true);
}, dataView.getUint32(INITIAL_ENTRY_POINTER_TO_POINTER), true);
}

@@ -1581,0 +1737,0 @@ /**

@@ -56,2 +56,9 @@ (function (global, factory) {

const REPLACE_DATA_VIEW_SYMBOL = Symbol("REPLACE_DATA_VIEW_SYMBOL");
const INTERNAL_API_SYMBOL = Symbol("INTERNAL_API");
const FIRST_FREE_BYTE_POINTER_TO_POINTER = 8;
const INITIAL_ENTRY_POINTER_TO_POINTER = 16;
const INITIAL_ENTRY_POINTER_VALUE = 24;
const primitives = ["string", "number", "bigint", "boolean", "undefined"];

@@ -87,3 +94,3 @@ function isPrimitive(value) {

return {
type: ENTRY_TYPE.BIGINT,
type: value >= BigInt("0") ? ENTRY_TYPE.BIGINT_POSITIVE : ENTRY_TYPE.BIGINT_NEGATIVE,
value

@@ -132,6 +139,13 @@ };

}
function getFirstFreeByte(arrayBuffer) {
return new DataView(arrayBuffer).getUint32(8);
function getFirstFreeByte(arrayBufferOrDataView) {
return (arrayBufferOrDataView instanceof DataView ? arrayBufferOrDataView : new DataView(arrayBufferOrDataView)).getUint32(FIRST_FREE_BYTE_POINTER_TO_POINTER);
}
function getOurPointerIfApplicable(value, ourDateView) {
const api = value[INTERNAL_API_SYMBOL];
if (api && api.getDataView() === ourDateView) {
return api.getEntryPointer();
}
}
let ENTRY_TYPE;

@@ -143,4 +157,4 @@

ENTRY_TYPE[ENTRY_TYPE["NUMBER"] = 2] = "NUMBER";
ENTRY_TYPE[ENTRY_TYPE["BIGINT"] = 3] = "BIGINT";
ENTRY_TYPE[ENTRY_TYPE["UBIGINT"] = 4] = "UBIGINT";
ENTRY_TYPE[ENTRY_TYPE["BIGINT_POSITIVE"] = 3] = "BIGINT_POSITIVE";
ENTRY_TYPE[ENTRY_TYPE["BIGINT_NEGATIVE"] = 4] = "BIGINT_NEGATIVE";
ENTRY_TYPE[ENTRY_TYPE["STRING"] = 5] = "STRING";

@@ -157,5 +171,37 @@ ENTRY_TYPE[ENTRY_TYPE["BOOLEAN"] = 6] = "BOOLEAN";

const PRIMITIVE_TYPES = [ENTRY_TYPE.NULL, ENTRY_TYPE.UNDEFINED, ENTRY_TYPE.NUMBER, ENTRY_TYPE.BIGINT, ENTRY_TYPE.UBIGINT, ENTRY_TYPE.BOOLEAN, ENTRY_TYPE.STRING];
const PRIMITIVE_TYPES = [ENTRY_TYPE.NULL, ENTRY_TYPE.UNDEFINED, ENTRY_TYPE.NUMBER, ENTRY_TYPE.BIGINT_POSITIVE, ENTRY_TYPE.BIGINT_NEGATIVE, ENTRY_TYPE.BOOLEAN, ENTRY_TYPE.STRING];
const isPrimitiveEntryType = createKnownTypeGuard(PRIMITIVE_TYPES);
class BigInt64OverflowError extends RangeError {
constructor() {
super("BigInt64OverflowError");
}
}
class IllegalObjectPropConfigError extends RangeError {
constructor() {
super("IllegalObjectPropConfigError");
}
}
class IllegalArrayIndexError extends RangeError {
constructor() {
super("IllegalArrayIndexError");
}
}
class UnsupportedOperationError extends Error {
constructor() {
super("UnsupportedOperationError");
}
}
class OutOfMemoryError extends Error {
constructor() {
super("OutOfMemoryError");
}
}
const MAX_64_BIG_INT = BigInt("0xFFFFFFFFFFFFFFFF");
function initializeArrayBuffer(arrayBuffer) {

@@ -166,5 +212,5 @@ const dataView = new DataView(arrayBuffer); // global lock

dataView.setUint32(8, 24); // first entry pointer
dataView.setUint32(FIRST_FREE_BYTE_POINTER_TO_POINTER, INITIAL_ENTRY_POINTER_VALUE); // first entry pointer
dataView.setUint32(16, 24);
dataView.setUint32(INITIAL_ENTRY_POINTER_TO_POINTER, INITIAL_ENTRY_POINTER_VALUE);
return dataView;

@@ -213,12 +259,12 @@ }

case ENTRY_TYPE.BIGINT:
dataView.setBigInt64(cursor, entry.value);
case ENTRY_TYPE.BIGINT_NEGATIVE:
case ENTRY_TYPE.BIGINT_POSITIVE:
if (entry.value > MAX_64_BIG_INT || entry.value < -MAX_64_BIG_INT) {
throw new BigInt64OverflowError();
}
dataView.setBigUint64(cursor, entry.type === ENTRY_TYPE.BIGINT_NEGATIVE ? -entry.value : entry.value);
cursor += BigInt64Array.BYTES_PER_ELEMENT;
break;
case ENTRY_TYPE.UBIGINT:
dataView.setBigUint64(cursor, entry.value);
cursor += BigUint64Array.BYTES_PER_ELEMENT;
break;
case ENTRY_TYPE.OBJECT:

@@ -270,9 +316,18 @@ dataView.setUint32(cursor, entry.value);

// End of data pointer
const firstFreeByte = dataView.getUint32(8);
const written = writeEntry(externalArgs, dataView, firstFreeByte, entry);
dataView.setUint32(8, firstFreeByte + written);
return {
start: firstFreeByte,
length: written
};
const firstFreeByte = dataView.getUint32(FIRST_FREE_BYTE_POINTER_TO_POINTER);
try {
const written = writeEntry(externalArgs, dataView, firstFreeByte, entry);
dataView.setUint32(FIRST_FREE_BYTE_POINTER_TO_POINTER, firstFreeByte + written);
return {
start: firstFreeByte,
length: written
};
} catch (e) {
if (e instanceof RangeError) {
// Assume Offset is outside the bounds of the DataView
// need to test it cross browser
throw new OutOfMemoryError();
} else throw e;
}
}

@@ -310,19 +365,25 @@ function readEntry(externalArgs, dataView, startingCursor) {

entry.allocatedBytes = dataView.getUint16(cursor);
cursor += Uint16Array.BYTES_PER_ELEMENT; // this wrapping is needed until:
// https://github.com/whatwg/encoding/issues/172
// eslint-disable-next-line no-case-declarations
cursor += Uint16Array.BYTES_PER_ELEMENT; // decode fails with zero length array
const tempAB = new ArrayBuffer(stringLength);
arrayBufferCopyTo(dataView.buffer, cursor, stringLength, tempAB, 0);
entry.value = externalArgs.textDecoder.decode(tempAB);
if (stringLength > 0) {
// this wrapping is needed until:
// https://github.com/whatwg/encoding/issues/172
// eslint-disable-next-line no-case-declarations
const tempAB = new ArrayBuffer(stringLength);
arrayBufferCopyTo(dataView.buffer, cursor, stringLength, tempAB, 0);
entry.value = externalArgs.textDecoder.decode(tempAB);
} else {
entry.value = "";
}
cursor += stringLength;
break;
case ENTRY_TYPE.BIGINT:
entry.value = dataView.getBigInt64(cursor);
cursor += BigInt64Array.BYTES_PER_ELEMENT;
case ENTRY_TYPE.BIGINT_POSITIVE:
entry.value = dataView.getBigUint64(cursor);
cursor += BigUint64Array.BYTES_PER_ELEMENT;
break;
case ENTRY_TYPE.UBIGINT:
entry.value = dataView.getBigUint64(cursor);
case ENTRY_TYPE.BIGINT_NEGATIVE:
entry.value = -dataView.getBigUint64(cursor);
cursor += BigUint64Array.BYTES_PER_ELEMENT;

@@ -376,5 +437,13 @@ break;

function reserveMemory(dataView, length) {
const firstFreeByte = dataView.getUint32(8);
dataView.setUint32(8, firstFreeByte + length);
return firstFreeByte;
try {
const allocatedMemoryAddress = dataView.getUint32(FIRST_FREE_BYTE_POINTER_TO_POINTER);
dataView.setUint32(FIRST_FREE_BYTE_POINTER_TO_POINTER, allocatedMemoryAddress + length);
return allocatedMemoryAddress;
} catch (e) {
if (e instanceof RangeError) {
// Assume Offset is outside the bounds of the DataView
// need to test it cross browser
throw new OutOfMemoryError();
} else throw e;
}
}

@@ -389,3 +458,3 @@ function canSaveValueIntoEntry(externalArgs, entryA, value) {

if ((entryA.type === ENTRY_TYPE.BIGINT || entryA.type === ENTRY_TYPE.UBIGINT || entryA.type === ENTRY_TYPE.NUMBER) && (typeofTheValue === "bigint" || typeofTheValue === "number")) {
if ((entryA.type === ENTRY_TYPE.BIGINT_NEGATIVE || entryA.type === ENTRY_TYPE.BIGINT_POSITIVE || entryA.type === ENTRY_TYPE.NUMBER) && (typeofTheValue === "bigint" || typeofTheValue === "number")) {
return true;

@@ -447,9 +516,6 @@ }

const GET_UNDERLYING_ARRAY_BUFFER_SYMBOL = Symbol("GET_UNDERLYING_ARRAY_BUFFER_SYMBOL");
const GET_UNDERLYING_POINTER_SYMBOL = Symbol("GET_UNDERLYING_POINTER_SYMBOL");
const REPLACE_DATA_VIEW_SYMBOL = Symbol("REPLACE_DATA_VIEW_SYMBOL");
function saveValue(externalArgs, dataView, value) {
let totalWrittenBytes = 0;
let valuePointer = 0;
let maybeOurPointer;

@@ -464,47 +530,29 @@ if (isPrimitive(value)) {

totalWrittenBytes += length;
} else if (maybeOurPointer = getOurPointerIfApplicable(value, dataView)) {
valuePointer = maybeOurPointer;
totalWrittenBytes += 0;
} else if (Array.isArray(value)) {
const maybeOurPointer = value[GET_UNDERLYING_POINTER_SYMBOL];
if (maybeOurPointer) {
valuePointer = maybeOurPointer;
totalWrittenBytes += 0;
} else {
const {
start,
length
} = arraySaver(externalArgs, dataView, value);
valuePointer = start;
totalWrittenBytes += length;
}
const {
start,
length
} = arraySaver(externalArgs, dataView, value);
valuePointer = start;
totalWrittenBytes += length;
} else if (value instanceof Date) {
const maybeOurPointer = value[GET_UNDERLYING_POINTER_SYMBOL];
if (maybeOurPointer) {
valuePointer = maybeOurPointer;
totalWrittenBytes += 0;
} else {
const {
start,
length
} = appendEntry(externalArgs, dataView, {
type: ENTRY_TYPE.DATE,
value: value.getTime()
});
valuePointer = start;
totalWrittenBytes += length;
}
const {
start,
length
} = appendEntry(externalArgs, dataView, {
type: ENTRY_TYPE.DATE,
value: value.getTime()
});
valuePointer = start;
totalWrittenBytes += length;
} else if (typeof value === "object") {
const maybeOurPointer = value[GET_UNDERLYING_POINTER_SYMBOL];
if (maybeOurPointer) {
valuePointer = maybeOurPointer;
totalWrittenBytes += 0;
} else {
const {
start,
length
} = objectSaver(externalArgs, dataView, value);
valuePointer = start;
totalWrittenBytes += length;
}
const {
start,
length
} = objectSaver(externalArgs, dataView, value);
valuePointer = start;
totalWrittenBytes += length;
} else {

@@ -554,119 +602,2 @@ throw new Error("unsupported yet");

function deleteObjectPropertyEntryByKey(externalArgs, dataView, containingObjectEntryPointer, keyToDeleteBy) {
invariant(containingObjectEntryPointer !== 0, "containingObjectEntryPointer Must not be 0");
const objectEntry = readEntry(externalArgs, dataView, containingObjectEntryPointer)[0];
if (objectEntry.value === 0) {
// Nothing to delete here
return false;
}
const firstPropEntry = readEntry(externalArgs, dataView, objectEntry.value)[0];
if (firstPropEntry.value.key === keyToDeleteBy) {
writeEntry(externalArgs, dataView, containingObjectEntryPointer, {
type: ENTRY_TYPE.OBJECT,
value: firstPropEntry.value.next
});
return true;
}
let entryToMaybeUpdate = firstPropEntry;
let entryToMaybeUpdatePointer = firstPropEntry.value.next;
let entryToMaybeDelete;
while (entryToMaybeUpdate.value.next !== 0) {
entryToMaybeDelete = readEntry(externalArgs, dataView, entryToMaybeUpdate.value.next)[0];
if (entryToMaybeDelete.value.key === keyToDeleteBy) {
break;
}
entryToMaybeUpdatePointer = entryToMaybeUpdate.value.next;
entryToMaybeUpdate = entryToMaybeDelete;
}
if (entryToMaybeDelete && entryToMaybeDelete.value.key === keyToDeleteBy) {
writeEntry(externalArgs, dataView, entryToMaybeUpdatePointer, {
type: ENTRY_TYPE.OBJECT_PROP,
value: {
key: entryToMaybeUpdate.value.key,
value: entryToMaybeUpdate.value.value,
next: entryToMaybeDelete.value.next
}
});
return true;
} else {
// key not found
return false;
} // Nothing to delete
}
/**
* If the object has no props, return the object pointer itself
* @param dataView
* @param containingObjectEntryPointer
* @param textDecoder
*/
function findLastObjectPropertyEntry(externalArgs, dataView, containingObjectEntryPointer) {
const [containingObjectEntry] = readEntry(externalArgs, dataView, containingObjectEntryPointer);
if (containingObjectEntry.value === 0) {
return [containingObjectEntryPointer, containingObjectEntry];
}
let nextElementPointer = containingObjectEntry.value; // eslint-disable-next-line no-constant-condition
while (true) {
const [objectPropEntry] = readEntry(externalArgs, dataView, nextElementPointer);
if (objectPropEntry.value.next === 0) {
return [nextElementPointer, objectPropEntry];
}
nextElementPointer = objectPropEntry.value.next;
}
}
function findObjectPropertyEntry(externalArgs, dataView, containingObjectEntryPointer, key) {
const [containingObjectEntry] = readEntry(externalArgs, dataView, containingObjectEntryPointer);
let currentPointer = containingObjectEntry.value;
let objectPropEntry;
if (containingObjectEntry.value === 0) {
return undefined;
} // eslint-disable-next-line no-constant-condition
while (true) {
[objectPropEntry] = readEntry(externalArgs, dataView, currentPointer);
if (objectPropEntry.value.key === key || objectPropEntry.value.next === 0) {
break;
}
currentPointer = objectPropEntry.value.next;
}
if (objectPropEntry.value.key === key) {
return [currentPointer, objectPropEntry];
}
return undefined;
}
function getObjectPropertiesEntries(externalArgs, dataView, containingObjectEntryPointer) {
const [containingObjectEntry] = readEntry(externalArgs, dataView, containingObjectEntryPointer);
const foundProps = [];
let nextElementPointer = containingObjectEntry.value;
let objectPropEntry;
do {
[objectPropEntry] = readEntry(externalArgs, dataView, nextElementPointer);
foundProps.push(objectPropEntry);
nextElementPointer = objectPropEntry.value.next;
} while (nextElementPointer !== 0);
return foundProps;
}
// isolated due to parser changes ts 3.7

@@ -919,2 +850,29 @@ // https://github.com/microsoft/TypeScript/pull/32695

/**
* Catches if the operation inside CB throw OOM exception,
* and if it did, restore the firstFreeByte & set everything to zero.
*
* For cases when we got oom in the middle of saving object, array, etc
*/
function handleOOM(operation, dataView) {
const prevFirstFreeByte = getFirstFreeByte(dataView.buffer);
try {
operation();
} catch (e) {
const currentFirstFreeByte = getFirstFreeByte(dataView.buffer); // restore prev state before the OOM operation
if (prevFirstFreeByte !== currentFirstFreeByte) {
dataView.setUint32(FIRST_FREE_BYTE_POINTER_TO_POINTER, prevFirstFreeByte);
for (let i = prevFirstFreeByte; i <= currentFirstFreeByte; i += 1) {
dataView.setUint8(i, 0);
}
}
throw e;
}
}
class ArrayWrapper {

@@ -928,4 +886,4 @@ constructor(externalArgs, dataViewCarrier, entryPointer) {

get(target, p) {
if (p === GET_UNDERLYING_POINTER_SYMBOL) {
return this.entryPointer;
if (p === INTERNAL_API_SYMBOL) {
return this;
}

@@ -978,2 +936,6 @@

if (!this.has(target, prop)) {
return undefined;
}
return {

@@ -997,4 +959,8 @@ configurable: false,

set(target, p, value) {
if (p === "length") {
set(target, accessedProp, value) {
if (typeof accessedProp === "symbol") {
throw new IllegalArrayIndexError();
}
if (accessedProp === "length") {
if (!Number.isSafeInteger(value) || value < 0) {

@@ -1010,28 +976,26 @@ throw new RangeError("Invalid array length");

if (currentLength > value) {
this.splice(value, currentLength - value);
return true;
}
handleOOM(() => {
if (currentLength > value) {
this.splice(value, currentLength - value);
return true;
}
extendArrayIfNeeded(this.externalArgs, this.dataViewCarrier.dataView, this.entryPointer, value);
extendArrayIfNeeded(this.externalArgs, this.dataViewCarrier.dataView, this.entryPointer, value);
}, this.dataViewCarrier.dataView);
return true;
}
extendArrayIfNeeded(this.externalArgs, this.dataViewCarrier.dataView, this.entryPointer, Number.parseInt(p, 10) + 1);
setValueAtArrayIndex(this.externalArgs, this.dataViewCarrier.dataView, this.entryPointer, Number.parseInt(p, 10), value);
return true;
}
const possibleIndex = Number.parseInt(accessedProp, 10);
isExtensible() {
if (!Number.isSafeInteger(possibleIndex) || possibleIndex < 0) {
throw new IllegalArrayIndexError();
}
handleOOM(() => {
extendArrayIfNeeded(this.externalArgs, this.dataViewCarrier.dataView, this.entryPointer, possibleIndex + 1);
setValueAtArrayIndex(this.externalArgs, this.dataViewCarrier.dataView, this.entryPointer, possibleIndex, value);
}, this.dataViewCarrier.dataView);
return true;
}
preventExtensions() {
throw new Error("unsupported");
}
setPrototypeOf() {
throw new Error("unsupported");
}
*entries() {

@@ -1100,2 +1064,34 @@ let index = 0;

getDataView() {
return this.dataViewCarrier.dataView;
}
getEntryPointer() {
return this.entryPointer;
}
isExtensible() {
return true;
}
preventExtensions() {
throw new UnsupportedOperationError();
}
setPrototypeOf() {
throw new UnsupportedOperationError();
}
defineProperty() {
throw new UnsupportedOperationError(); // if (
// typeof p === "symbol" ||
// attributes.enumerable === false ||
// attributes.get ||
// attributes.set
// ) {
// throw new IllegalObjectPropConfigError();
// }
// return Object.defineProperty(target, p, attributes);
}
}

@@ -1121,2 +1117,6 @@ function createArrayWrapper(externalArgs, dataViewCarrier, entryPointer) {

get(target, p) {
if (p === INTERNAL_API_SYMBOL) {
return this;
}
if (getFunctions.includes(p)) {

@@ -1159,2 +1159,22 @@ if (!(p in this.useMeToGiveNamesToFunctionsAndCacheThem)) {

getDataView() {
return this.dataViewCarrier.dataView;
}
getEntryPointer() {
return this.entryPointer;
}
defineProperty() {
throw new UnsupportedOperationError();
}
setPrototypeOf() {
throw new UnsupportedOperationError();
}
isExtensible() {
return false;
}
}

@@ -1235,2 +1255,179 @@ function createDateWrapper(externalArgs, dataViewCarrier, entryPointer) {

function deleteObjectPropertyEntryByKey(externalArgs, dataView, containingObjectEntryPointer, keyToDeleteBy) {
invariant(containingObjectEntryPointer !== 0, "containingObjectEntryPointer Must not be 0");
const objectEntry = readEntry(externalArgs, dataView, containingObjectEntryPointer)[0];
if (objectEntry.value === 0) {
// Nothing to delete here
return false;
}
const firstPropEntry = readEntry(externalArgs, dataView, objectEntry.value)[0];
if (firstPropEntry.value.key === keyToDeleteBy) {
writeEntry(externalArgs, dataView, containingObjectEntryPointer, {
type: ENTRY_TYPE.OBJECT,
value: firstPropEntry.value.next
});
return true;
}
let entryToMaybeUpdate = firstPropEntry;
let entryToMaybeUpdatePointer = firstPropEntry.value.next;
let entryToMaybeDelete;
while (entryToMaybeUpdate.value.next !== 0) {
entryToMaybeDelete = readEntry(externalArgs, dataView, entryToMaybeUpdate.value.next)[0];
if (entryToMaybeDelete.value.key === keyToDeleteBy) {
break;
}
entryToMaybeUpdatePointer = entryToMaybeUpdate.value.next;
entryToMaybeUpdate = entryToMaybeDelete;
}
if (entryToMaybeDelete && entryToMaybeDelete.value.key === keyToDeleteBy) {
writeEntry(externalArgs, dataView, entryToMaybeUpdatePointer, {
type: ENTRY_TYPE.OBJECT_PROP,
value: {
key: entryToMaybeUpdate.value.key,
value: entryToMaybeUpdate.value.value,
next: entryToMaybeDelete.value.next
}
});
return true;
} else {
// key not found
return false;
} // Nothing to delete
}
/**
* If the object has no props, return the object pointer itself
* @param dataView
* @param containingObjectEntryPointer
* @param textDecoder
*/
function findLastObjectPropertyEntry(externalArgs, dataView, containingObjectEntryPointer) {
const [containingObjectEntry] = readEntry(externalArgs, dataView, containingObjectEntryPointer);
if (containingObjectEntry.value === 0) {
return [containingObjectEntryPointer, containingObjectEntry];
}
let nextElementPointer = containingObjectEntry.value; // eslint-disable-next-line no-constant-condition
while (true) {
const [objectPropEntry] = readEntry(externalArgs, dataView, nextElementPointer);
if (objectPropEntry.value.next === 0) {
return [nextElementPointer, objectPropEntry];
}
nextElementPointer = objectPropEntry.value.next;
}
}
function findObjectPropertyEntry(externalArgs, dataView, containingObjectEntryPointer, key) {
const [containingObjectEntry] = readEntry(externalArgs, dataView, containingObjectEntryPointer);
let currentPointer = containingObjectEntry.value;
let objectPropEntry; // eslint-disable-next-line no-constant-condition
while (currentPointer !== 0) {
[objectPropEntry] = readEntry(externalArgs, dataView, currentPointer);
if (objectPropEntry.value.key === key || objectPropEntry.value.next === 0) {
break;
}
currentPointer = objectPropEntry.value.next;
}
if (objectPropEntry && objectPropEntry.value.key === key) {
return [currentPointer, objectPropEntry];
}
return undefined;
}
function getObjectPropertiesEntries(externalArgs, dataView, containingObjectEntryPointer) {
const [containingObjectEntry] = readEntry(externalArgs, dataView, containingObjectEntryPointer);
const foundProps = [];
let nextElementPointer = containingObjectEntry.value;
let objectPropEntry;
if (nextElementPointer === 0) {
return [];
}
do {
[objectPropEntry] = readEntry(externalArgs, dataView, nextElementPointer);
foundProps.push(objectPropEntry);
nextElementPointer = objectPropEntry.value.next;
} while (nextElementPointer !== 0);
return foundProps;
}
function objectSet(externalArgs, dataView, entryPointer, p, value) {
const foundPropEntry = findObjectPropertyEntry(externalArgs, dataView, entryPointer, p); // new prop
if (foundPropEntry === undefined) {
const {
start: newValueEntryPointer
} = saveValue(externalArgs, dataView, value);
const {
start: newPropEntryPointer
} = appendEntry(externalArgs, dataView, {
type: ENTRY_TYPE.OBJECT_PROP,
value: {
next: 0,
value: newValueEntryPointer,
key: p
}
});
const [lastItemPointer, lastItemEntry] = findLastObjectPropertyEntry(externalArgs, dataView, entryPointer);
if (lastItemEntry.type === ENTRY_TYPE.OBJECT) {
writeEntry(externalArgs, dataView, lastItemPointer, {
type: ENTRY_TYPE.OBJECT,
value: newPropEntryPointer
});
} else {
writeEntry(externalArgs, dataView, lastItemPointer, {
type: ENTRY_TYPE.OBJECT_PROP,
value: {
next: newPropEntryPointer,
value: lastItemEntry.value.value,
key: lastItemEntry.value.key
}
});
}
} else {
if (!overwriteEntryIfPossible(externalArgs, dataView, foundPropEntry[1].value.value, value)) {
const {
start: newValueEntryPointer
} = saveValue(externalArgs, dataView, value); // overwrite value
writeEntry(externalArgs, dataView, foundPropEntry[0], {
type: ENTRY_TYPE.OBJECT_PROP,
value: {
key: foundPropEntry[1].value.key,
next: foundPropEntry[1].value.next,
value: newValueEntryPointer
}
});
}
}
}
function objectGet(externalArgs, dataView, entryPointer, p) {
const foundEntry = findObjectPropertyEntry(externalArgs, dataView, entryPointer, p);
if (foundEntry === undefined) {
return undefined;
}
const [valueEntry] = readEntry(externalArgs, dataView, foundEntry[1].value.value);
return entryToFinalJavaScriptValue(externalArgs, dataView, valueEntry, foundEntry[1].value.value);
}
class ObjectWrapper {

@@ -1248,15 +1445,3 @@ constructor(externalArgs, dataViewCarrier, entryPointer, isTopLevel) {

getUnderlyingArrayBuffer() {
if (!this.isTopLevel) {
throw new Error("Only Supported on Top Level");
}
return this.dataViewCarrier.dataView.buffer;
}
get(target, p) {
if (p === GET_UNDERLYING_ARRAY_BUFFER_SYMBOL) {
return this.getUnderlyingArrayBuffer();
}
if (p === REPLACE_DATA_VIEW_SYMBOL) {

@@ -1266,4 +1451,4 @@ return this.replaceDataView.bind(this);

if (p === GET_UNDERLYING_POINTER_SYMBOL) {
return this.entryPointer;
if (p === INTERNAL_API_SYMBOL) {
return this;
} /// empty object

@@ -1276,13 +1461,3 @@

const foundEntry = findObjectPropertyEntry(this.externalArgs, this.dataViewCarrier.dataView, this.entryPointer, // Add validation ?
// eslint-disable-next-line @typescript-eslint/ban-ts-ignore
// @ts-ignore
p);
if (foundEntry === undefined) {
return undefined;
}
const [valueEntry] = readEntry(this.externalArgs, this.dataViewCarrier.dataView, foundEntry[1].value.value);
return entryToFinalJavaScriptValue(this.externalArgs, this.dataViewCarrier.dataView, valueEntry, foundEntry[1].value.value);
return objectGet(this.externalArgs, this.dataViewCarrier.dataView, this.entryPointer, p);
}

@@ -1304,11 +1479,19 @@

getOwnPropertyDescriptor() {
return {
configurable: true,
enumerable: true
};
getOwnPropertyDescriptor(target, p) {
if (this.has(target, p)) {
return {
configurable: true,
enumerable: true
};
}
return undefined;
}
has(target, p) {
/// empty object
if (typeof p === "symbol") {
throw new IllegalObjectPropConfigError();
} /// empty object
if (this.entry.value === 0) {

@@ -1318,6 +1501,3 @@ return false;

const foundEntry = findObjectPropertyEntry(this.externalArgs, this.dataViewCarrier.dataView, this.entry.value, // Add validation ?
// eslint-disable-next-line @typescript-eslint/ban-ts-ignore
// @ts-ignore
p);
const foundEntry = findObjectPropertyEntry(this.externalArgs, this.dataViewCarrier.dataView, this.entryPointer, p);
return foundEntry !== undefined;

@@ -1327,52 +1507,9 @@ }

set(target, p, value) {
const foundPropEntry = findObjectPropertyEntry(this.externalArgs, this.dataViewCarrier.dataView, this.entryPointer, p); // new prop
if (foundPropEntry === undefined) {
const {
start: newValueEntryPointer
} = saveValue(this.externalArgs, this.dataViewCarrier.dataView, value);
const {
start: newPropEntryPointer
} = appendEntry(this.externalArgs, this.dataViewCarrier.dataView, {
type: ENTRY_TYPE.OBJECT_PROP,
value: {
next: 0,
value: newValueEntryPointer,
key: p
}
});
const [lastItemPointer, lastItemEntry] = findLastObjectPropertyEntry(this.externalArgs, this.dataViewCarrier.dataView, this.entryPointer);
if (lastItemEntry.type === ENTRY_TYPE.OBJECT) {
writeEntry(this.externalArgs, this.dataViewCarrier.dataView, lastItemPointer, {
type: ENTRY_TYPE.OBJECT,
value: newPropEntryPointer
});
} else {
writeEntry(this.externalArgs, this.dataViewCarrier.dataView, lastItemPointer, {
type: ENTRY_TYPE.OBJECT_PROP,
value: {
next: newPropEntryPointer,
value: lastItemEntry.value.value,
key: lastItemEntry.value.key
}
});
}
} else {
if (!overwriteEntryIfPossible(this.externalArgs, this.dataViewCarrier.dataView, foundPropEntry[1].value.value, value)) {
const {
start: newValueEntryPointer
} = saveValue(this.externalArgs, this.dataViewCarrier.dataView, value); // overwrite value
writeEntry(this.externalArgs, this.dataViewCarrier.dataView, foundPropEntry[0], {
type: ENTRY_TYPE.OBJECT_PROP,
value: {
key: foundPropEntry[1].value.key,
next: foundPropEntry[1].value.next,
value: newValueEntryPointer
}
});
}
if (typeof p === "symbol") {
throw new IllegalObjectPropConfigError();
}
handleOOM(() => {
objectSet(this.externalArgs, this.dataViewCarrier.dataView, this.entryPointer, p, value);
}, this.dataViewCarrier.dataView);
return true;

@@ -1386,7 +1523,7 @@ }

preventExtensions() {
throw new Error("unsupported");
throw new UnsupportedOperationError();
}
setPrototypeOf() {
throw new Error("unsupported");
throw new UnsupportedOperationError();
} // getPrototypeOf? (target: T): object | null;

@@ -1401,4 +1538,15 @@ // setPrototypeOf? (target: T, v: any): boolean;

// deleteProperty? (target: T, p: PropertyKey): boolean;
// defineProperty? (target: T, p: PropertyKey, attributes: PropertyDescriptor): boolean;
// enumerate? (target: T): PropertyKey[];
defineProperty() {
throw new UnsupportedOperationError(); // if (
// typeof p === "symbol" ||
// attributes.enumerable === false ||
// attributes.get ||
// attributes.set
// ) {
// throw new IllegalObjectPropConfigError();
// }
// return Object.defineProperty(target, p, attributes);
} // enumerate? (target: T): PropertyKey[];
// ownKeys? (target: T): PropertyKey[];

@@ -1413,2 +1561,10 @@ // apply? (target: T, thisArg: any, argArray?: any): any;

getDataView() {
return this.dataViewCarrier.dataView;
}
getEntryPointer() {
return this.entryPointer;
}
}

@@ -1546,3 +1702,3 @@ function createObjectWrapper(externalArgs, dataViewCarrier, entryPointer, isTopLevel = false) {

} = objectSaver(externalArgsApiToExternalArgsApi(externalArgs), dataView, initialValue);
dataView.setUint32(16, start);
dataView.setUint32(INITIAL_ENTRY_POINTER_TO_POINTER, start);
return createObjectWrapper(externalArgsApiToExternalArgsApi(externalArgs), {

@@ -1567,3 +1723,3 @@ dataView

function getUnderlyingArrayBuffer(objectBuffer) {
return objectBuffer[GET_UNDERLYING_ARRAY_BUFFER_SYMBOL];
return objectBuffer[INTERNAL_API_SYMBOL].getDataView().buffer;
}

@@ -1584,3 +1740,3 @@ /**

dataView
}, dataView.getUint32(16), true);
}, dataView.getUint32(INITIAL_ENTRY_POINTER_TO_POINTER), true);
}

@@ -1587,0 +1743,0 @@ /**

{
"name": "@bnaya/objectbuffer",
"description": "Object-like api, backed by an array buffer",
"version": "0.8.0",
"version": "0.9.0",
"main": "dist/objectbuffer.cjs.js",

@@ -62,3 +62,3 @@ "module": "dist/index.js",

"typedoc-plugin-markdown": "^2.2.10",
"typescript": "^3.7.0-dev.20191004",
"typescript": "^3.7.0-dev.20191013",
"webpack": "^4.41.0",

@@ -65,0 +65,0 @@ "webpack-cli": "^3.3.9",

@@ -10,4 +10,6 @@ # ObjectBuffer: object-like API, backed by a [shared]arraybuffer

The library is still not `1.0`, but usable, and will never offer full compatibility with plain js (`Symbol` and such)
The library is still not `1.0`, but already usable, and will never offer full compatibility with plain js (`Symbol` and such)
For in-depth overview of how things are implemented, see [implementation details document](docs/implementationDetails.md)
## Quick example

@@ -57,2 +59,7 @@

## Why not [FlatBuffers](https://github.com/google/flatbuffers)
For many cases FlatBuffers is the right tool!
FlatBuffers requires full re-serialization when changing values. inside. The api is also more different than javascript objects.
## Disclaimer / Motivation

@@ -59,0 +66,0 @@

@@ -30,7 +30,5 @@ import { ExternalArgs } from "../internal/interfaces";

objectBuffer.num = -BigInt(
"0b0111111111111111111111111111111111111111111111111111111111111111"
);
objectBuffer.num = -BigInt("18446744073709551615");
objectBuffer.num--;
objectBuffer.num++;

@@ -50,3 +48,3 @@ memoryAfterEachOperation.push(getFirstFreeByte(ab));

Object {
"num": -9223372036854775808n,
"num": -18446744073709551614n,
}

@@ -53,0 +51,0 @@ `);

import { initializeArrayBuffer } from "./store";
import { objectSaver } from "./objectSaver";
import { createObjectWrapper } from "./objectWrapper";
import {
GET_UNDERLYING_ARRAY_BUFFER_SYMBOL,
REPLACE_DATA_VIEW_SYMBOL
} from "./symbols";
import { ExternalArgs } from "./interfaces";
import { INTERNAL_API_SYMBOL, REPLACE_DATA_VIEW_SYMBOL } from "./symbols";
import { ExternalArgs, InternalAPI } from "./interfaces";
import { arrayBufferCopyTo, getFirstFreeByte } from "./utils";
import { getCacheFor } from "./externalObjectsCache";
import { TextDecoder, TextEncoder } from "./textEncoderDecoderTypes";
import { INITIAL_ENTRY_POINTER_TO_POINTER } from "./consts";

@@ -45,3 +43,3 @@ export interface CreateObjectBufferOptions {

dataView.setUint32(16, start);
dataView.setUint32(INITIAL_ENTRY_POINTER_TO_POINTER, start);

@@ -82,3 +80,4 @@ return createObjectWrapper(

): ArrayBuffer | SharedArrayBuffer {
return objectBuffer[GET_UNDERLYING_ARRAY_BUFFER_SYMBOL];
return (objectBuffer[INTERNAL_API_SYMBOL] as InternalAPI).getDataView()
.buffer;
}

@@ -104,3 +103,3 @@

{ dataView },
dataView.getUint32(16),
dataView.getUint32(INITIAL_ENTRY_POINTER_TO_POINTER),
true

@@ -107,0 +106,0 @@ );

@@ -9,5 +9,10 @@ import {

} from "./arrayHelpers";
import { GET_UNDERLYING_POINTER_SYMBOL } from "./symbols";
import { INTERNAL_API_SYMBOL } from "./symbols";
import { arraySplice } from "./arraySplice";
import { ExternalArgs, DataViewCarrier } from "./interfaces";
import {
IllegalArrayIndexError,
UnsupportedOperationError
} from "./exceptions";
import { handleOOM } from "./handleOOM";

@@ -22,4 +27,4 @@ export class ArrayWrapper implements ProxyHandler<{}> {

public get(target: {}, p: PropertyKey): any {
if (p === GET_UNDERLYING_POINTER_SYMBOL) {
return this.entryPointer;
if (p === INTERNAL_API_SYMBOL) {
return this;
}

@@ -84,2 +89,6 @@

if (!this.has(target, prop)) {
return undefined;
}
return { configurable: false, enumerable: true };

@@ -104,4 +113,8 @@ }

public set(target: {}, p: PropertyKey, value: any): boolean {
if (p === "length") {
public set(target: {}, accessedProp: PropertyKey, value: any): boolean {
if (typeof accessedProp === "symbol") {
throw new IllegalArrayIndexError();
}
if (accessedProp === "length") {
if (!Number.isSafeInteger(value) || value < 0) {

@@ -121,8 +134,27 @@ throw new RangeError("Invalid array length");

if (currentLength > value) {
this.splice(value, currentLength - value);
handleOOM(() => {
if (currentLength > value) {
this.splice(value, currentLength - value);
return true;
}
return true;
}
extendArrayIfNeeded(
this.externalArgs,
this.dataViewCarrier.dataView,
this.entryPointer,
value
);
}, this.dataViewCarrier.dataView);
return true;
}
const possibleIndex = Number.parseInt(accessedProp as string, 10);
if (!Number.isSafeInteger(possibleIndex) || possibleIndex < 0) {
throw new IllegalArrayIndexError();
}
handleOOM(() => {
extendArrayIfNeeded(

@@ -132,38 +164,17 @@ this.externalArgs,

this.entryPointer,
possibleIndex + 1
);
setValueAtArrayIndex(
this.externalArgs,
this.dataViewCarrier.dataView,
this.entryPointer,
possibleIndex,
value
);
}, this.dataViewCarrier.dataView);
return true;
}
extendArrayIfNeeded(
this.externalArgs,
this.dataViewCarrier.dataView,
this.entryPointer,
Number.parseInt(p as string, 10) + 1
);
setValueAtArrayIndex(
this.externalArgs,
this.dataViewCarrier.dataView,
this.entryPointer,
Number.parseInt(p as string, 10),
value
);
return true;
}
public isExtensible() {
return true;
}
public preventExtensions(): boolean {
throw new Error("unsupported");
}
public setPrototypeOf(): boolean {
throw new Error("unsupported");
}
public *entries(): Iterable<[number, any]> {

@@ -285,2 +296,39 @@ let index = 0;

}
public getDataView() {
return this.dataViewCarrier.dataView;
}
public getEntryPointer() {
return this.entryPointer;
}
public isExtensible() {
return true;
}
public preventExtensions(): boolean {
throw new UnsupportedOperationError();
}
public setPrototypeOf(): boolean {
throw new UnsupportedOperationError();
}
public defineProperty(): // target: {},
// p: PropertyKey,
// attributes: PropertyDescriptor
boolean {
throw new UnsupportedOperationError();
// if (
// typeof p === "symbol" ||
// attributes.enumerable === false ||
// attributes.get ||
// attributes.set
// ) {
// throw new IllegalObjectPropConfigError();
// }
// return Object.defineProperty(target, p, attributes);
}
}

@@ -287,0 +335,0 @@

@@ -5,2 +5,4 @@ import { ExternalArgs, DataViewCarrier, DateEntry } from "./interfaces";

import { ENTRY_TYPE } from "./entry-types";
import { INTERNAL_API_SYMBOL } from "./symbols";
import { UnsupportedOperationError } from "./exceptions";

@@ -73,2 +75,6 @@ const getFunctions: Array<keyof Date> = [

get(target: Date, p: PropertyKey) {
if (p === INTERNAL_API_SYMBOL) {
return this;
}
if (getFunctions.includes(p as any)) {

@@ -120,2 +126,22 @@ if (!(p in this.useMeToGiveNamesToFunctionsAndCacheThem)) {

}
public getDataView() {
return this.dataViewCarrier.dataView;
}
public getEntryPointer() {
return this.entryPointer;
}
public defineProperty(): boolean {
throw new UnsupportedOperationError();
}
public setPrototypeOf(): boolean {
throw new UnsupportedOperationError();
}
public isExtensible() {
return false;
}
}

@@ -122,0 +148,0 @@

@@ -16,4 +16,4 @@ /* eslint-env jest */

"2": "NUMBER",
"3": "BIGINT",
"4": "UBIGINT",
"3": "BIGINT_POSITIVE",
"4": "BIGINT_NEGATIVE",
"5": "STRING",

@@ -26,3 +26,4 @@ "6": "BOOLEAN",

"ARRAY_ITEM": 10,
"BIGINT": 3,
"BIGINT_NEGATIVE": 4,
"BIGINT_POSITIVE": 3,
"BOOLEAN": 6,

@@ -37,3 +38,2 @@ "DATE": 13,

"STRING": 5,
"UBIGINT": 4,
"UNDEFINED": 0,

@@ -40,0 +40,0 @@ }

@@ -7,4 +7,4 @@ import { createKnownTypeGuard } from "./utils";

NUMBER,
BIGINT,
UBIGINT,
BIGINT_POSITIVE,
BIGINT_NEGATIVE,
STRING,

@@ -25,4 +25,4 @@ BOOLEAN,

ENTRY_TYPE.NUMBER,
ENTRY_TYPE.BIGINT,
ENTRY_TYPE.UBIGINT,
ENTRY_TYPE.BIGINT_POSITIVE,
ENTRY_TYPE.BIGINT_NEGATIVE,
ENTRY_TYPE.BOOLEAN,

@@ -29,0 +29,0 @@ ENTRY_TYPE.STRING

@@ -12,4 +12,4 @@ import { ENTRY_TYPE } from "./entry-types";

| NumberEntry
| BigIntEntry
| UBigIntEntry
| BigIntPositiveEntry
| BigIntNegativeEntry
| ObjectEntry

@@ -44,9 +44,9 @@ | ObjectPropEntry

export interface BigIntEntry {
type: ENTRY_TYPE.BIGINT;
export interface BigIntPositiveEntry {
type: ENTRY_TYPE.BIGINT_POSITIVE;
value: bigint;
}
export interface UBigIntEntry {
type: ENTRY_TYPE.UBIGINT;
export interface BigIntNegativeEntry {
type: ENTRY_TYPE.BIGINT_NEGATIVE;
value: bigint;

@@ -107,1 +107,6 @@ }

}>;
export interface InternalAPI {
getDataView(): DataView;
getEntryPointer(): number;
}
import { ObjectEntry, ExternalArgs, DataViewCarrier } from "./interfaces";
import { readEntry } from "./store";
import {
readEntry,
writeEntry,
appendEntry,
overwriteEntryIfPossible
} from "./store";
import { ENTRY_TYPE } from "./entry-types";
import {
findObjectPropertyEntry,
getObjectPropertiesEntries,
deleteObjectPropertyEntryByKey,
findLastObjectPropertyEntry
objectGet,
objectSet
} from "./objectWrapperHelpers";
import { saveValue } from "./saveValue";
import { entryToFinalJavaScriptValue } from "./entryToFinalJavaScriptValue";
import { REPLACE_DATA_VIEW_SYMBOL, INTERNAL_API_SYMBOL } from "./symbols";
import {
GET_UNDERLYING_ARRAY_BUFFER_SYMBOL,
GET_UNDERLYING_POINTER_SYMBOL,
REPLACE_DATA_VIEW_SYMBOL
} from "./symbols";
IllegalObjectPropConfigError,
UnsupportedOperationError
} from "./exceptions";
import { handleOOM } from "./handleOOM";

@@ -36,15 +30,3 @@ export class ObjectWrapper implements ProxyHandler<{}> {

private getUnderlyingArrayBuffer() {
if (!this.isTopLevel) {
throw new Error("Only Supported on Top Level");
}
return this.dataViewCarrier.dataView.buffer;
}
public get(target: {}, p: PropertyKey): any {
if (p === GET_UNDERLYING_ARRAY_BUFFER_SYMBOL) {
return this.getUnderlyingArrayBuffer();
}
if (p === REPLACE_DATA_VIEW_SYMBOL) {

@@ -54,4 +36,4 @@ return this.replaceDataView.bind(this);

if (p === GET_UNDERLYING_POINTER_SYMBOL) {
return this.entryPointer;
if (p === INTERNAL_API_SYMBOL) {
return this;
}

@@ -64,28 +46,8 @@

const foundEntry = findObjectPropertyEntry(
return objectGet(
this.externalArgs,
this.dataViewCarrier.dataView,
this.entryPointer,
// Add validation ?
// eslint-disable-next-line @typescript-eslint/ban-ts-ignore
// @ts-ignore
p
p as string
);
if (foundEntry === undefined) {
return undefined;
}
const [valueEntry] = readEntry(
this.externalArgs,
this.dataViewCarrier.dataView,
foundEntry[1].value.value
);
return entryToFinalJavaScriptValue(
this.externalArgs,
this.dataViewCarrier.dataView,
valueEntry,
foundEntry[1].value.value
);
}

@@ -98,3 +60,3 @@

this.entryPointer,
p as any
p as string
);

@@ -123,7 +85,15 @@ }

public getOwnPropertyDescriptor() {
return { configurable: true, enumerable: true };
public getOwnPropertyDescriptor(target: {}, p: PropertyKey) {
if (this.has(target, p)) {
return { configurable: true, enumerable: true };
}
return undefined;
}
public has(target: {}, p: PropertyKey) {
if (typeof p === "symbol") {
throw new IllegalObjectPropConfigError();
}
/// empty object

@@ -137,7 +107,4 @@ if (this.entry.value === 0) {

this.dataViewCarrier.dataView,
this.entry.value,
// Add validation ?
// eslint-disable-next-line @typescript-eslint/ban-ts-ignore
// @ts-ignore
p
this.entryPointer,
p as string
);

@@ -149,93 +116,16 @@

public set(target: {}, p: PropertyKey, value: any): boolean {
const foundPropEntry = findObjectPropertyEntry(
this.externalArgs,
this.dataViewCarrier.dataView,
this.entryPointer,
p as string
);
if (typeof p === "symbol") {
throw new IllegalObjectPropConfigError();
}
// new prop
if (foundPropEntry === undefined) {
const { start: newValueEntryPointer } = saveValue(
handleOOM(() => {
objectSet(
this.externalArgs,
this.dataViewCarrier.dataView,
this.entryPointer,
p as string,
value
);
}, this.dataViewCarrier.dataView);
const { start: newPropEntryPointer } = appendEntry(
this.externalArgs,
this.dataViewCarrier.dataView,
{
type: ENTRY_TYPE.OBJECT_PROP,
value: {
next: 0,
value: newValueEntryPointer,
key: p as string
}
}
);
const [lastItemPointer, lastItemEntry] = findLastObjectPropertyEntry(
this.externalArgs,
this.dataViewCarrier.dataView,
this.entryPointer
);
if (lastItemEntry.type === ENTRY_TYPE.OBJECT) {
writeEntry(
this.externalArgs,
this.dataViewCarrier.dataView,
lastItemPointer,
{
type: ENTRY_TYPE.OBJECT,
value: newPropEntryPointer
}
);
} else {
writeEntry(
this.externalArgs,
this.dataViewCarrier.dataView,
lastItemPointer,
{
type: ENTRY_TYPE.OBJECT_PROP,
value: {
next: newPropEntryPointer,
value: lastItemEntry.value.value,
key: lastItemEntry.value.key
}
}
);
}
} else {
if (
!overwriteEntryIfPossible(
this.externalArgs,
this.dataViewCarrier.dataView,
foundPropEntry[1].value.value,
value
)
) {
const { start: newValueEntryPointer } = saveValue(
this.externalArgs,
this.dataViewCarrier.dataView,
value
);
// overwrite value
writeEntry(
this.externalArgs,
this.dataViewCarrier.dataView,
foundPropEntry[0],
{
type: ENTRY_TYPE.OBJECT_PROP,
value: {
key: foundPropEntry[1].value.key,
next: foundPropEntry[1].value.next,
value: newValueEntryPointer
}
}
);
}
}
return true;

@@ -249,7 +139,7 @@ }

public preventExtensions(): boolean {
throw new Error("unsupported");
throw new UnsupportedOperationError();
}
public setPrototypeOf(): boolean {
throw new Error("unsupported");
throw new UnsupportedOperationError();
}

@@ -266,3 +156,18 @@

// deleteProperty? (target: T, p: PropertyKey): boolean;
// defineProperty? (target: T, p: PropertyKey, attributes: PropertyDescriptor): boolean;
public defineProperty(): // target: {},
// p: PropertyKey,
// attributes: PropertyDescriptor
boolean {
throw new UnsupportedOperationError();
// if (
// typeof p === "symbol" ||
// attributes.enumerable === false ||
// attributes.get ||
// attributes.set
// ) {
// throw new IllegalObjectPropConfigError();
// }
// return Object.defineProperty(target, p, attributes);
}
// enumerate? (target: T): PropertyKey[];

@@ -280,2 +185,10 @@ // ownKeys? (target: T): PropertyKey[];

}
public getDataView() {
return this.dataViewCarrier.dataView;
}
public getEntryPointer() {
return this.entryPointer;
}
}

@@ -282,0 +195,0 @@

import { ObjectEntry, ObjectPropEntry, ExternalArgs } from "./interfaces";
import { readEntry, writeEntry } from "./store";
import {
readEntry,
writeEntry,
appendEntry,
overwriteEntryIfPossible
} from "./store";
import { invariant } from "./utils";
import { ENTRY_TYPE } from "./entry-types";
import { entryToFinalJavaScriptValue } from "./entryToFinalJavaScriptValue";
import { saveValue } from "./saveValue";

@@ -135,8 +142,4 @@ export function deleteObjectPropertyEntryByKey(

if (containingObjectEntry.value === 0) {
return undefined;
}
// eslint-disable-next-line no-constant-condition
while (true) {
while (currentPointer !== 0) {
[objectPropEntry] = readEntry(externalArgs, dataView, currentPointer) as [

@@ -154,3 +157,3 @@ ObjectPropEntry,

if (objectPropEntry.value.key === key) {
if (objectPropEntry && objectPropEntry.value.key === key) {
return [currentPointer, objectPropEntry];

@@ -174,2 +177,6 @@ }

if (containingObjectEntry.value === 0) {
return undefined;
}
let nextElementPointer = containingObjectEntry.value;

@@ -211,2 +218,6 @@ let objectPropEntry: ObjectPropEntry | undefined;

if (nextElementPointer === 0) {
return [];
}
do {

@@ -226,1 +237,112 @@ [objectPropEntry] = readEntry(

}
export function objectSet(
externalArgs: ExternalArgs,
dataView: DataView,
entryPointer: number,
p: string,
value: any
) {
const foundPropEntry = findObjectPropertyEntry(
externalArgs,
dataView,
entryPointer,
p as string
);
// new prop
if (foundPropEntry === undefined) {
const { start: newValueEntryPointer } = saveValue(
externalArgs,
dataView,
value
);
const { start: newPropEntryPointer } = appendEntry(externalArgs, dataView, {
type: ENTRY_TYPE.OBJECT_PROP,
value: {
next: 0,
value: newValueEntryPointer,
key: p as string
}
});
const [lastItemPointer, lastItemEntry] = findLastObjectPropertyEntry(
externalArgs,
dataView,
entryPointer
);
if (lastItemEntry.type === ENTRY_TYPE.OBJECT) {
writeEntry(externalArgs, dataView, lastItemPointer, {
type: ENTRY_TYPE.OBJECT,
value: newPropEntryPointer
});
} else {
writeEntry(externalArgs, dataView, lastItemPointer, {
type: ENTRY_TYPE.OBJECT_PROP,
value: {
next: newPropEntryPointer,
value: lastItemEntry.value.value,
key: lastItemEntry.value.key
}
});
}
} else {
if (
!overwriteEntryIfPossible(
externalArgs,
dataView,
foundPropEntry[1].value.value,
value
)
) {
const { start: newValueEntryPointer } = saveValue(
externalArgs,
dataView,
value
);
// overwrite value
writeEntry(externalArgs, dataView, foundPropEntry[0], {
type: ENTRY_TYPE.OBJECT_PROP,
value: {
key: foundPropEntry[1].value.key,
next: foundPropEntry[1].value.next,
value: newValueEntryPointer
}
});
}
}
}
export function objectGet(
externalArgs: ExternalArgs,
dataView: DataView,
entryPointer: number,
p: string
) {
const foundEntry = findObjectPropertyEntry(
externalArgs,
dataView,
entryPointer,
p
);
if (foundEntry === undefined) {
return undefined;
}
const [valueEntry] = readEntry(
externalArgs,
dataView,
foundEntry[1].value.value
);
return entryToFinalJavaScriptValue(
externalArgs,
dataView,
valueEntry,
foundEntry[1].value.value
);
}

@@ -1,6 +0,9 @@

import { primitiveValueToEntry, isPrimitive } from "./utils";
import {
primitiveValueToEntry,
isPrimitive,
getOurPointerIfApplicable
} from "./utils";
import { appendEntry } from "./store";
import { objectSaver } from "./objectSaver";
import { arraySaver } from "./arraySaver";
import { GET_UNDERLYING_POINTER_SYMBOL } from "./symbols";
import { ExternalArgs } from "./interfaces";

@@ -16,2 +19,3 @@ import { ENTRY_TYPE } from "./entry-types";

let valuePointer = 0;
let maybeOurPointer: number | undefined;

@@ -28,39 +32,22 @@ if (isPrimitive(value)) {

totalWrittenBytes += length;
} else if ((maybeOurPointer = getOurPointerIfApplicable(value, dataView))) {
valuePointer = maybeOurPointer;
totalWrittenBytes += 0;
} else if (Array.isArray(value)) {
const maybeOurPointer = value[GET_UNDERLYING_POINTER_SYMBOL as any];
if (maybeOurPointer) {
valuePointer = maybeOurPointer;
totalWrittenBytes += 0;
} else {
const { start, length } = arraySaver(externalArgs, dataView, value);
const { start, length } = arraySaver(externalArgs, dataView, value);
valuePointer = start;
totalWrittenBytes += length;
}
valuePointer = start;
totalWrittenBytes += length;
} else if (value instanceof Date) {
const maybeOurPointer = (value as any)[GET_UNDERLYING_POINTER_SYMBOL];
const { start, length } = appendEntry(externalArgs, dataView, {
type: ENTRY_TYPE.DATE,
value: value.getTime()
});
if (maybeOurPointer) {
valuePointer = maybeOurPointer;
totalWrittenBytes += 0;
} else {
const { start, length } = appendEntry(externalArgs, dataView, {
type: ENTRY_TYPE.DATE,
value: value.getTime()
});
valuePointer = start;
totalWrittenBytes += length;
}
valuePointer = start;
totalWrittenBytes += length;
} else if (typeof value === "object") {
const maybeOurPointer = value[GET_UNDERLYING_POINTER_SYMBOL as any];
if (maybeOurPointer) {
valuePointer = maybeOurPointer;
totalWrittenBytes += 0;
} else {
const { start, length } = objectSaver(externalArgs, dataView, value);
valuePointer = start;
totalWrittenBytes += length;
}
const { start, length } = objectSaver(externalArgs, dataView, value);
valuePointer = start;
totalWrittenBytes += length;
} else {

@@ -67,0 +54,0 @@ throw new Error("unsupported yet");

@@ -241,3 +241,3 @@ /* eslint-env jest */

const writtenByteLength = writeEntry(externalArgs, dataView, 0, {
type: ENTRY_TYPE.BIGINT,
type: ENTRY_TYPE.BIGINT_POSITIVE,
value: BigInt("0b0" + "1".repeat(63))

@@ -263,3 +263,3 @@ });

const writtenByteLength = writeEntry(externalArgs, dataView, 0, {
type: ENTRY_TYPE.UBIGINT,
type: ENTRY_TYPE.BIGINT_POSITIVE,
value: BigInt("0b" + "1".repeat(64))

@@ -274,3 +274,3 @@ });

Object {
"type": 4,
"type": 3,
"value": 18446744073709551615n,

@@ -280,3 +280,54 @@ }

});
test("ENTRY_TYPE.BIGINT_POSITIVE max value", () => {
const arrayBuffer = new ArrayBuffer(16);
const dataView = new DataView(arrayBuffer);
writeEntry(externalArgs, dataView, 0, {
type: ENTRY_TYPE.BIGINT_POSITIVE,
value: BigInt("0b" + "1".repeat(64))
});
expect(readEntry(externalArgs, dataView, 0)).toMatchInlineSnapshot(`
Array [
Object {
"type": 3,
"value": 18446744073709551615n,
},
9,
]
`);
});
test("ENTRY_TYPE.BIGINT_NEGATIVE min value", () => {
const arrayBuffer = new ArrayBuffer(16);
const dataView = new DataView(arrayBuffer);
writeEntry(externalArgs, dataView, 0, {
type: ENTRY_TYPE.BIGINT_NEGATIVE,
value: -BigInt("0b" + "1".repeat(64))
});
expect(readEntry(externalArgs, dataView, 0)).toMatchInlineSnapshot(`
Array [
Object {
"type": 4,
"value": -18446744073709551615n,
},
9,
]
`);
});
test("BigInt64 overflow error", () => {
const arrayBuffer = new ArrayBuffer(16);
const dataView = new DataView(arrayBuffer);
expect(() => {
writeEntry(externalArgs, dataView, 0, {
type: ENTRY_TYPE.BIGINT_POSITIVE,
value: BigInt("0b" + "1".repeat(65))
});
}).toThrowErrorMatchingInlineSnapshot(`"BigInt64OverflowError"`);
});
describe("Store tests write/read entry", () => {

@@ -283,0 +334,0 @@ test("object entry", () => {

@@ -5,3 +5,11 @@ import { ENTRY_TYPE } from "./entry-types";

import { ExternalArgs } from "./interfaces";
import { BigInt64OverflowError, OutOfMemoryError } from "./exceptions";
import {
FIRST_FREE_BYTE_POINTER_TO_POINTER,
INITIAL_ENTRY_POINTER_TO_POINTER,
INITIAL_ENTRY_POINTER_VALUE
} from "./consts";
const MAX_64_BIG_INT = BigInt("0xFFFFFFFFFFFFFFFF");
export function initializeArrayBuffer(arrayBuffer: ArrayBuffer) {

@@ -14,6 +22,12 @@ const dataView = new DataView(arrayBuffer);

// End of data pointer / first free byte
dataView.setUint32(8, 24);
dataView.setUint32(
FIRST_FREE_BYTE_POINTER_TO_POINTER,
INITIAL_ENTRY_POINTER_VALUE
);
// first entry pointer
dataView.setUint32(16, 24);
dataView.setUint32(
INITIAL_ENTRY_POINTER_TO_POINTER,
INITIAL_ENTRY_POINTER_VALUE
);

@@ -75,12 +89,15 @@ return dataView;

case ENTRY_TYPE.BIGINT:
dataView.setBigInt64(cursor, entry.value);
case ENTRY_TYPE.BIGINT_NEGATIVE:
case ENTRY_TYPE.BIGINT_POSITIVE:
if (entry.value > MAX_64_BIG_INT || entry.value < -MAX_64_BIG_INT) {
throw new BigInt64OverflowError();
}
dataView.setBigUint64(
cursor,
entry.type === ENTRY_TYPE.BIGINT_NEGATIVE ? -entry.value : entry.value
);
cursor += BigInt64Array.BYTES_PER_ELEMENT;
break;
case ENTRY_TYPE.UBIGINT:
dataView.setBigUint64(cursor, entry.value);
cursor += BigUint64Array.BYTES_PER_ELEMENT;
break;
case ENTRY_TYPE.OBJECT:

@@ -140,11 +157,24 @@ dataView.setUint32(cursor, entry.value);

// End of data pointer
const firstFreeByte = dataView.getUint32(8);
const firstFreeByte = dataView.getUint32(FIRST_FREE_BYTE_POINTER_TO_POINTER);
const written = writeEntry(externalArgs, dataView, firstFreeByte, entry);
dataView.setUint32(8, firstFreeByte + written);
try {
const written = writeEntry(externalArgs, dataView, firstFreeByte, entry);
return {
start: firstFreeByte,
length: written
};
dataView.setUint32(
FIRST_FREE_BYTE_POINTER_TO_POINTER,
firstFreeByte + written
);
return {
start: firstFreeByte,
length: written
};
} catch (e) {
if (e instanceof RangeError) {
// Assume Offset is outside the bounds of the DataView
// need to test it cross browser
throw new OutOfMemoryError();
} else throw e;
}
}

@@ -194,9 +224,14 @@

// this wrapping is needed until:
// https://github.com/whatwg/encoding/issues/172
// eslint-disable-next-line no-case-declarations
const tempAB = new ArrayBuffer(stringLength);
arrayBufferCopyTo(dataView.buffer, cursor, stringLength, tempAB, 0);
// decode fails with zero length array
if (stringLength > 0) {
// this wrapping is needed until:
// https://github.com/whatwg/encoding/issues/172
// eslint-disable-next-line no-case-declarations
const tempAB = new ArrayBuffer(stringLength);
arrayBufferCopyTo(dataView.buffer, cursor, stringLength, tempAB, 0);
entry.value = externalArgs.textDecoder.decode(tempAB);
entry.value = externalArgs.textDecoder.decode(tempAB);
} else {
entry.value = "";
}

@@ -207,9 +242,9 @@ cursor += stringLength;

case ENTRY_TYPE.BIGINT:
entry.value = dataView.getBigInt64(cursor);
cursor += BigInt64Array.BYTES_PER_ELEMENT;
case ENTRY_TYPE.BIGINT_POSITIVE:
entry.value = dataView.getBigUint64(cursor);
cursor += BigUint64Array.BYTES_PER_ELEMENT;
break;
case ENTRY_TYPE.UBIGINT:
entry.value = dataView.getBigUint64(cursor);
case ENTRY_TYPE.BIGINT_NEGATIVE:
entry.value = -dataView.getBigUint64(cursor);
cursor += BigUint64Array.BYTES_PER_ELEMENT;

@@ -273,7 +308,21 @@ break;

export function reserveMemory(dataView: DataView, length: number) {
const firstFreeByte = dataView.getUint32(8);
try {
const allocatedMemoryAddress = dataView.getUint32(
FIRST_FREE_BYTE_POINTER_TO_POINTER
);
dataView.setUint32(8, firstFreeByte + length);
dataView.setUint32(
FIRST_FREE_BYTE_POINTER_TO_POINTER,
allocatedMemoryAddress + length
);
return firstFreeByte;
return allocatedMemoryAddress;
} catch (e) {
if (e instanceof RangeError) {
// Assume Offset is outside the bounds of the DataView
// need to test it cross browser
throw new OutOfMemoryError();
} else throw e;
}
}

@@ -294,4 +343,4 @@

if (
(entryA.type === ENTRY_TYPE.BIGINT ||
entryA.type === ENTRY_TYPE.UBIGINT ||
(entryA.type === ENTRY_TYPE.BIGINT_NEGATIVE ||
entryA.type === ENTRY_TYPE.BIGINT_POSITIVE ||
entryA.type === ENTRY_TYPE.NUMBER) &&

@@ -298,0 +347,0 @@ (typeofTheValue === "bigint" || typeofTheValue === "number")

@@ -10,1 +10,3 @@ export const GET_UNDERLYING_ARRAY_BUFFER_SYMBOL = Symbol(

export const REPLACE_DATA_VIEW_SYMBOL = Symbol("REPLACE_DATA_VIEW_SYMBOL");
export const INTERNAL_API_SYMBOL = Symbol("INTERNAL_API");

@@ -0,1 +1,3 @@

import { FIRST_FREE_BYTE_POINTER_TO_POINTER } from "./consts";
export function arrayBuffer2HexArray(

@@ -17,3 +19,5 @@ buffer: ArrayBuffer,

export function getFirstFreeByte(arrayBuffer: ArrayBuffer) {
return new DataView(arrayBuffer).getUint32(8);
return new DataView(arrayBuffer).getUint32(
FIRST_FREE_BYTE_POINTER_TO_POINTER
);
}

@@ -1,3 +0,5 @@

import { primitive, Entry, ExternalArgs } from "./interfaces";
import { primitive, Entry, ExternalArgs, InternalAPI } from "./interfaces";
import { ENTRY_TYPE } from "./entry-types";
import { INTERNAL_API_SYMBOL } from "./symbols";
import { FIRST_FREE_BYTE_POINTER_TO_POINTER } from "./consts";

@@ -49,3 +51,6 @@ const primitives = [

return {
type: ENTRY_TYPE.BIGINT,
type:
value >= BigInt("0")
? ENTRY_TYPE.BIGINT_POSITIVE
: ENTRY_TYPE.BIGINT_NEGATIVE,
value

@@ -104,4 +109,16 @@ };

export function getFirstFreeByte(arrayBuffer: ArrayBuffer) {
return new DataView(arrayBuffer).getUint32(8);
export function getFirstFreeByte(
arrayBufferOrDataView: DataView | ArrayBuffer
) {
return (arrayBufferOrDataView instanceof DataView
? arrayBufferOrDataView
: new DataView(arrayBufferOrDataView)
).getUint32(FIRST_FREE_BYTE_POINTER_TO_POINTER);
}
export function getOurPointerIfApplicable(value: any, ourDateView: DataView) {
const api: InternalAPI | undefined = value[INTERNAL_API_SYMBOL];
if (api && api.getDataView() === ourDateView) {
return api.getEntryPointer();
}
}

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc