UNPKG

json-as

Version:

The only JSON library you'll need for AssemblyScript. SIMD enabled

199 lines (176 loc) 6.21 kB
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 @inline 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 @inline 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 @inline 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 @inline 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 @inline 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 @inline 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 @inline 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 @inline 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 @inline 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 @inline 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); } }