json-as
Version:
The only JSON library you'll need for AssemblyScript. SIMD enabled
199 lines (176 loc) • 6.21 kB
text/typescript
import { OBJECT, TOTAL_OVERHEAD } from "rt/common";
const SHRINK_EVERY_N: u32 = 200;
const MIN_BUFFER_SIZE: u32 = 128;
/**
* Central buffer namespace for managing memory operations.
*/
export namespace bs {
/** Current buffer pointer. */
export let buffer: ArrayBuffer = new ArrayBuffer(MIN_BUFFER_SIZE);
/** Current offset within the buffer. */
export let offset: usize = changetype<usize>(buffer);
/** Byte length of the buffer. */
let bufferSize: usize = MIN_BUFFER_SIZE;
/** Proposed size of output */
export let stackSize: usize = 0;
let pauseOffset: usize = 0;
let pauseStackSize: usize = 0;
let typicalSize: u32 = MIN_BUFFER_SIZE;
let counter: u32 = 0;
/**
* Stores the state of the buffer, allowing further changes to be reset
*/
// @ts-ignore: decorator
export function saveState(): void {
pauseOffset = offset;
pauseStackSize = stackSize;
}
/**
* Resets the buffer to the state it was in when `pause()` was called.
* This allows for changes made after the pause to be discarded.
*/
// @ts-ignore: decorator
export function loadState(): void {
offset = pauseOffset;
stackSize = pauseStackSize;
}
/**
* Resets the buffer to the state it was in when `pause()` was called.
* This allows for changes made after the pause to be discarded.
*/
// @ts-ignore: decorator
export function resetState(): void {
offset = pauseOffset;
stackSize = pauseStackSize;
pauseOffset = 0;
}
/**
* Proposes that the buffer size is should be greater than or equal to the proposed size.
* If necessary, reallocates the buffer to the exact new size.
* @param size - The size to propose.
*/
// @ts-ignore: decorator
export function ensureSize(size: u32): void {
if (offset + size > bufferSize + changetype<usize>(buffer)) {
const deltaBytes = size + MIN_BUFFER_SIZE;
bufferSize += deltaBytes;
// @ts-ignore: exists
const newPtr = changetype<ArrayBuffer>(__renew(changetype<usize>(buffer), bufferSize));
offset = offset + changetype<usize>(newPtr) - changetype<usize>(buffer);
buffer = newPtr;
}
}
/**
* Proposes that the buffer size is should be greater than or equal to the proposed size.
* If necessary, reallocates the buffer to the exact new size.
* @param size - The size to propose.
*/
// @ts-ignore: decorator
export function proposeSize(size: u32): void {
if ((stackSize += size) > bufferSize) {
const deltaBytes = size;
bufferSize += deltaBytes;
// @ts-ignore: exists
const newPtr = changetype<ArrayBuffer>(__renew(changetype<usize>(buffer), bufferSize));
offset = offset + changetype<usize>(newPtr) - changetype<usize>(buffer);
buffer = newPtr;
}
}
/**
* Increases the proposed size by n + MIN_BUFFER_SIZE if necessary.
* If necessary, reallocates the buffer to the exact new size.
* @param size - The size to grow by.
*/
// @ts-ignore: decorator
export function growSize(size: u32): void {
if ((stackSize += size) > bufferSize) {
const deltaBytes = size + MIN_BUFFER_SIZE;
bufferSize += deltaBytes;
// @ts-ignore
const newPtr = changetype<ArrayBuffer>(__renew(changetype<usize>(buffer), bufferSize));
offset = offset + changetype<usize>(newPtr) - changetype<usize>(buffer);
buffer = newPtr;
}
}
/**
* Resizes the buffer to the specified size.
* @param newSize - The new buffer size.
*/
// @ts-ignore: Decorator valid here
export function resize(newSize: u32): void {
// @ts-ignore: exists
const newPtr = changetype<ArrayBuffer>(__renew(changetype<usize>(buffer), newSize));
bufferSize = newSize;
offset = changetype<usize>(newPtr);
buffer = newPtr;
stackSize = 0;
}
/**
* Copies the buffer's content to a new object of a specified type. Does not shrink the buffer.
* @returns The new object containing the buffer's content.
*/
// @ts-ignore: Decorator valid here
export function cpyOut<T>(): T {
if (pauseOffset == 0) {
const len = offset - changetype<usize>(buffer);
// @ts-ignore: exists
const _out = __new(len, idof<T>());
memory.copy(_out, changetype<usize>(buffer), len);
return changetype<T>(_out);
} else {
const len = offset - pauseOffset;
// @ts-ignore: exists
const _out = __new(len, idof<T>());
memory.copy(_out, pauseOffset, len);
bs.loadState();
return changetype<T>(_out);
}
}
/**
* Copies the buffer's content to a new object of a specified type.
* @returns The new object containing the buffer's content.
*/
// @ts-ignore: Decorator valid here
export function out<T>(): T {
const len = offset - changetype<usize>(buffer);
// @ts-ignore: exists
const _out = __new(len, idof<T>());
memory.copy(_out, changetype<usize>(buffer), len);
counter++;
typicalSize = (typicalSize + <u32>len) >> 1;
if (counter >= SHRINK_EVERY_N) {
if (bufferSize > typicalSize << 2) {
resize(typicalSize << 1);
}
counter = 0;
}
offset = changetype<usize>(buffer);
stackSize = 0;
return changetype<T>(_out);
}
/**
* Copies the buffer's content to a given destination pointer.
* Optionally shrinks the buffer after copying.
* @param dst - The destination pointer.
* @param s - Whether to shrink the buffer after copying.
* @returns The destination pointer cast to the specified type.
*/
// @ts-ignore: Decorator valid here
export function outTo<T>(dst: usize): T {
const len = offset - changetype<usize>(buffer);
// @ts-ignore: exists
if (len != changetype<OBJECT>(dst - TOTAL_OVERHEAD).rtSize) __renew(len, idof<T>());
memory.copy(dst, changetype<usize>(buffer), len);
counter++;
typicalSize = (typicalSize + len) >> 1;
if (counter >= SHRINK_EVERY_N) {
if (bufferSize > typicalSize << 2) {
resize(typicalSize << 1);
}
counter = 0;
}
offset = changetype<usize>(buffer);
stackSize = 0;
return changetype<T>(dst);
}
}