mirror of
https://github.com/vercel-labs/scriptc.git
synced 2026-10-02 00:25:34 +08:00
feat: support static Float64Array (#391)
- Add Float64Array construction, storage, and access across compiler backends and runtime. - Cover precision, views, methods, and dynamic boundaries with differential fixtures.
This commit is contained in:
@@ -1498,7 +1498,7 @@ export class CEmitter {
|
||||
`}`,
|
||||
);
|
||||
}
|
||||
if ([...this.bytesElementHelpers].some((key) => key.startsWith("set:") && key.split(":")[1] !== "f32")) {
|
||||
if ([...this.bytesElementHelpers].some((key) => key.startsWith("set:") && !key.startsWith("set:f32:") && !key.startsWith("set:f64:"))) {
|
||||
out.push(
|
||||
`static inline uint32_t sc_bytes_coerce_u32(double v) {`,
|
||||
` if (v >= -9007199254740992.0 && v <= 9007199254740992.0) return (uint32_t)(int64_t)v;`,
|
||||
@@ -1509,7 +1509,7 @@ export class CEmitter {
|
||||
`}`,
|
||||
);
|
||||
}
|
||||
for (const elem of ["u8", "u32", "i32", "f32"] as const) {
|
||||
for (const elem of ["u8", "u32", "i32", "f32", "f64"] as const) {
|
||||
for (const mode of ["f64", "u64"] as const) {
|
||||
const suffix = mode === "u64" ? "_u64" : "";
|
||||
const indexType = mode === "u64" ? "uint64_t" : "double";
|
||||
@@ -1522,11 +1522,12 @@ export class CEmitter {
|
||||
`}`,
|
||||
);
|
||||
} else {
|
||||
const valueType = elem === "f32" ? "float" : elem === "i32" ? "int32_t" : "uint32_t";
|
||||
const valueType = elem === "f32" ? "float" : elem === "f64" ? "double" : elem === "i32" ? "int32_t" : "uint32_t";
|
||||
const size = elem === "f64" ? 8 : 4;
|
||||
out.push(
|
||||
`static inline double sc_bytes_get_${elem}${suffix}(const ScrBytes *b, ${indexType} i) {`,
|
||||
` ${valueType} v;`,
|
||||
` memcpy(&v, b->data + ${checked}(b, i) * 4, 4);`,
|
||||
` memcpy(&v, b->data + ${checked}(b, i) * ${size}, ${size});`,
|
||||
` return (double)v;`,
|
||||
`}`,
|
||||
);
|
||||
@@ -1540,13 +1541,14 @@ export class CEmitter {
|
||||
`}`,
|
||||
);
|
||||
} else {
|
||||
const valueType = elem === "f32" ? "float" : "uint32_t";
|
||||
const init = elem === "f32" ? `(float)v` : `sc_bytes_coerce_u32(v)`;
|
||||
const valueType = elem === "f32" ? "float" : elem === "f64" ? "double" : "uint32_t";
|
||||
const init = elem === "f32" ? `(float)v` : elem === "f64" ? "v" : `sc_bytes_coerce_u32(v)`;
|
||||
const size = elem === "f64" ? 8 : 4;
|
||||
out.push(
|
||||
`static inline void sc_bytes_set_${elem}${suffix}(ScrBytes *b, ${indexType} i, double v) {`,
|
||||
` size_t idx = ${checked}(b, i);`,
|
||||
` ${valueType} stored = ${init};`,
|
||||
` memcpy(b->data + idx * 4, &stored, 4);`,
|
||||
` memcpy(b->data + idx * ${size}, &stored, ${size});`,
|
||||
`}`,
|
||||
);
|
||||
}
|
||||
|
||||
@@ -1941,7 +1941,7 @@ function emitContainerExpr(
|
||||
}
|
||||
return emitter.newTemp(
|
||||
e.type,
|
||||
`(double)(${r.name}->len * ${e.receiver.type.elem === "u8" ? "1" : "4"})`,
|
||||
`(double)(${r.name}->len * ${e.receiver.type.elem === "u8" ? "1" : e.receiver.type.elem === "f64" ? "8" : "4"})`,
|
||||
);
|
||||
case "get":
|
||||
// Any invalid index traps (the array runtime's discipline).
|
||||
|
||||
@@ -4,7 +4,7 @@ import { InternalCompilerError } from "../../errors.js";
|
||||
* array element kinds, map key/value kinds), plus C literal spelling. Pure
|
||||
* functions of IrType/values — every emission module leans on these, so they
|
||||
* live in ONE place with no emitter state. */
|
||||
import type { IrType } from "../../ir/ir.js";
|
||||
import type { IrBytesElem, IrType } from "../../ir/ir.js";
|
||||
import { POINTER_KINDS, type PointerKind, runtimeRcStem, RUNTIME_EMITTER_CLASS, RUNTIME_ERROR_CLASSES, RUNTIME_STREAM_CLASSES } from "../../ir/ir.js";
|
||||
import {
|
||||
mangleClassRelease,
|
||||
@@ -329,8 +329,16 @@ export function elemKindC(elem: IrType): string {
|
||||
}
|
||||
|
||||
/** The runtime's element-kind tag for a bytes (typed array) type. */
|
||||
export function bytesElemKindC(elem: "u8" | "u32" | "i32" | "f32"): string {
|
||||
return elem === "u8" ? "SCR_BYTES_U8" : elem === "u32" ? "SCR_BYTES_U32" : elem === "i32" ? "SCR_BYTES_I32" : "SCR_BYTES_F32";
|
||||
const BYTES_ELEM_KIND_C: Record<IrBytesElem, string> = {
|
||||
u8: "SCR_BYTES_U8",
|
||||
u32: "SCR_BYTES_U32",
|
||||
i32: "SCR_BYTES_I32",
|
||||
f32: "SCR_BYTES_F32",
|
||||
f64: "SCR_BYTES_F64",
|
||||
};
|
||||
|
||||
export function bytesElemKindC(elem: IrBytesElem): string {
|
||||
return BYTES_ELEM_KIND_C[elem];
|
||||
}
|
||||
|
||||
/** The runtime's ScrBytesNumKind tag + littleEndian flag per readNum/
|
||||
|
||||
@@ -145,7 +145,7 @@ export function emitBytesLength(host: LlvmEmitterContext, elem: IrBytesElem, rec
|
||||
B.line(`${p} = getelementptr inbounds %ScrBytes, ptr ${receiver}, i64 0, i32 1`);
|
||||
B.line(`${len} = load ${host.sizeType}, ptr ${p}`);
|
||||
const count = bytes && elem !== "u8" ? B.tmp() : len;
|
||||
if (count !== len) B.line(`${count} = shl ${host.sizeType} ${len}, 2`);
|
||||
if (count !== len) B.line(`${count} = shl ${host.sizeType} ${len}, ${elem === "f64" ? 3 : 2}`);
|
||||
const out = B.tmp();
|
||||
B.line(`${out} = uitofp ${host.sizeType} ${count} to double`);
|
||||
return { name: out, type: F64 };
|
||||
@@ -174,6 +174,12 @@ export function emitBytesGet(host: LlvmEmitterContext, elem: IrBytesElem, receiv
|
||||
B.line(`${out} = fpext float ${raw} to double`);
|
||||
return { name: out, type: F64 };
|
||||
}
|
||||
if (elem === "f64") {
|
||||
const out = B.tmp();
|
||||
B.line(`${p} = getelementptr inbounds double, ptr ${data}, ${host.sizeType} ${idx}`);
|
||||
B.line(`${out} = load double, ptr ${p}, align 1`);
|
||||
return { name: out, type: F64 };
|
||||
}
|
||||
const raw = B.tmp();
|
||||
const out = B.tmp();
|
||||
B.line(`${p} = getelementptr inbounds i32, ptr ${data}, ${host.sizeType} ${idx}`);
|
||||
@@ -252,7 +258,7 @@ export function emitToUint32(host: LlvmEmitterContext, value: string): string {
|
||||
export function emitBytesSet(host: LlvmEmitterContext, elem: IrBytesElem, receiver: string, index: string, value: string, integerIndex = false): void {
|
||||
const B = host.B;
|
||||
const idx = host.emitBytesIndex(receiver, index, integerIndex);
|
||||
const stored = elem === "f32" ? null : host.emitToUint32(value);
|
||||
const stored = elem === "f32" || elem === "f64" ? null : host.emitToUint32(value);
|
||||
const data = host.emitBytesData(receiver);
|
||||
const p = B.tmp();
|
||||
if (elem === "u8") {
|
||||
@@ -269,6 +275,11 @@ export function emitBytesSet(host: LlvmEmitterContext, elem: IrBytesElem, receiv
|
||||
B.line(`store float ${narrowed}, ptr ${p}, align 1`);
|
||||
return;
|
||||
}
|
||||
if (elem === "f64") {
|
||||
B.line(`${p} = getelementptr inbounds double, ptr ${data}, ${host.sizeType} ${idx}`);
|
||||
B.line(`store double ${value}, ptr ${p}, align 1`);
|
||||
return;
|
||||
}
|
||||
B.line(`${p} = getelementptr inbounds i32, ptr ${data}, ${host.sizeType} ${idx}`);
|
||||
B.line(`store i32 ${stored!}, ptr ${p}, align 1`);
|
||||
}
|
||||
|
||||
@@ -1,18 +1,19 @@
|
||||
/* Focused LLVM expression emission extracted from emitter.ts. */
|
||||
import { InternalCompilerError } from "../../errors.js";
|
||||
import { matchStringSelfConcat, undefinedArmTag } from "../../ir/analysis.js";
|
||||
import { isRefCounted } from "../../ir/ir.js";
|
||||
import { isRefCounted, type IrBytesElem } from "../../ir/ir.js";
|
||||
import { mangleRecordClone, mangleRecordNew } from "../mangle.js";
|
||||
import { arrNewCall, elemAccess } from "./shapes.js";
|
||||
import { LlvmUnsupportedError } from "./unsupported.js";
|
||||
import type { LlvmEmitterContext, ExprOf, LlValue } from "./expr-context.js";
|
||||
|
||||
/** ScrBytesElem (scr_runtime.h): U8, U32, F32, I32. */
|
||||
const BYTES_ELEM_NUM: Record<"u8" | "u32" | "f32" | "i32", number> = {
|
||||
/** ScrBytesElem (scr_runtime.h): U8, U32, F32, I32, F64. */
|
||||
const BYTES_ELEM_NUM: Record<IrBytesElem, number> = {
|
||||
u8: 0,
|
||||
u32: 1,
|
||||
f32: 2,
|
||||
i32: 3,
|
||||
f64: 4,
|
||||
};
|
||||
import { f64Lit } from "./common.js";
|
||||
|
||||
|
||||
@@ -96,16 +96,17 @@ function lowerBytesToSortedCall(
|
||||
/* ── typed arrays / Buffer ─────────────────────────────────────────────── */
|
||||
|
||||
/** The typed-array constructors with a runtime representation, by lib
|
||||
* interface name. The other TypedArray flavors (Int8Array, Float64Array,
|
||||
* DataView, ...) fall through to the generic stdlib-constructor fence. */
|
||||
* interface name. Other flavors (Int8Array, Float16Array, ...) fall through
|
||||
* to the generic stdlib-constructor fence. DataView is handled separately. */
|
||||
const BYTES_CTORS: Record<string, IrBytesElem | undefined> = {
|
||||
Uint8Array: "u8",
|
||||
Uint32Array: "u32",
|
||||
Int32Array: "i32",
|
||||
Float32Array: "f32",
|
||||
Float64Array: "f64",
|
||||
};
|
||||
|
||||
/** `new Uint8Array(...)` / `new Uint32Array(...)` / `new Float32Array(...)`
|
||||
/** `new Uint8Array(...)` / `new Uint32Array(...)` / `new Float32Array(...)` / `new Float64Array(...)`
|
||||
* (stdlib provenance — a user's own class with the name resolves through
|
||||
* classBySymbol). Lowered argument shapes: none (empty), a length
|
||||
* (zero-filled; ToIndex at runtime — invalid lengths throw Node's
|
||||
@@ -163,7 +164,7 @@ export function lowerBytesNew(lowerer: Lowerer, expr: ts.NewExpression, symbol:
|
||||
"erases into the view): drop the options bag",
|
||||
);
|
||||
}
|
||||
const elemSize = elem === "u8" ? 1 : 4;
|
||||
const elemSize = elem === "u8" ? 1 : elem === "f64" ? 8 : 4;
|
||||
const lenArg = argNode.arguments?.length === 1 ? argNode.arguments[0] : undefined;
|
||||
const lenT = lenArg ? lowerer.typeOf(lenArg) : null;
|
||||
const byteLen = lenT?.isNumberLiteralType() ? lenT.value : null;
|
||||
@@ -284,7 +285,7 @@ function lowerDataViewNew(lowerer: Lowerer, expr: ts.NewExpression): IrExpr {
|
||||
}
|
||||
const hint =
|
||||
"views compile over a typed array's own storage — new DataView(x.buffer, byteOffset?, byteLength?) " +
|
||||
"where x is a Uint8Array/Uint32Array/Float32Array/Buffer value — or a fresh buffer erased into " +
|
||||
"where x is a Uint8Array/Uint32Array/Float32Array/Float64Array/Buffer value — or a fresh buffer erased into " +
|
||||
"the view: new DataView(new ArrayBuffer(n), ...); free-standing ArrayBuffers have no representation";
|
||||
if (!ts.isPropertyAccessExpression(bufNode) || bufNode.name.text !== "buffer" || bufNode.questionDotToken) {
|
||||
lowerer.noLowering("new DataView over this buffer expression", bufNode, hint);
|
||||
|
||||
@@ -5180,8 +5180,8 @@ export function lowerNew(lowerer: Lowerer, expr: ts.NewExpression): IrExpr {
|
||||
);
|
||||
}
|
||||
// `new Uint8Array(...)` / `new Uint32Array(...)` / `new
|
||||
// Float32Array(...)`: the typed-array constructors with a runtime
|
||||
// representation (stdlib provenance — see lowerBytesNew for the
|
||||
// Float32Array(...)` / `new Float64Array(...)`: the typed-array
|
||||
// constructors with a runtime representation (stdlib provenance — see lowerBytesNew for the
|
||||
// lowered argument shapes; a user's own class with one of the names
|
||||
// resolves through classBySymbol below).
|
||||
const bytesNew = lowerer.lowerBytesNew(expr, symbol);
|
||||
|
||||
@@ -430,7 +430,7 @@ export function formatIrType(t: IrType, shapes: ShapeRegistry, unions: UnionRegi
|
||||
case "bytes":
|
||||
// The u8 kind reads as Uint8Array (Buffer maps here too — one
|
||||
// runtime representation; the message stays honest either way).
|
||||
return t.elem === "u8" ? "Uint8Array" : t.elem === "u32" ? "Uint32Array" : t.elem === "i32" ? "Int32Array" : "Float32Array";
|
||||
return t.elem === "u8" ? "Uint8Array" : t.elem === "u32" ? "Uint32Array" : t.elem === "i32" ? "Int32Array" : t.elem === "f32" ? "Float32Array" : "Float64Array";
|
||||
case "map":
|
||||
return `Map<${formatIrType(t.key, shapes, unions, seen)}, ${formatIrType(t.value, shapes, unions, seen)}>`;
|
||||
case "set":
|
||||
@@ -1702,10 +1702,10 @@ function mapTypeInner(type: ts.Type, ctx: TypeMapperCtx): IrType | null {
|
||||
return { kind: "regex" };
|
||||
}
|
||||
// Typed arrays: references to the lib's Uint8Array/Uint32Array/
|
||||
// Float32Array interfaces (provenance, not names). The es2022+ lib
|
||||
// Float32Array/Float64Array interfaces (provenance, not names). The es2022+ lib
|
||||
// declares them generic over the backing buffer (`Uint8Array<ArrayBuffer>`
|
||||
// in error text) — the type argument is irrelevant here: no views exist,
|
||||
// every value owns its storage. The other TypedArray flavors stay
|
||||
// in error text) — the type argument is irrelevant here: no free-standing
|
||||
// ArrayBuffer value exists. The other TypedArray flavors stay
|
||||
// unmapped (the record path's index-signature check rejects them).
|
||||
// RegExpMatchArray (s.match's result) IS a string[] here — the honest
|
||||
// slice: [whole match, ...captures] (a nonparticipating capture reads
|
||||
@@ -1741,6 +1741,7 @@ function mapTypeInner(type: ts.Type, ctx: TypeMapperCtx): IrType | null {
|
||||
// SharedArrayBuffer, and the i32 semantics hold for every other use.
|
||||
if (isStdlibInterface("Int32Array")) return bytesOf("i32");
|
||||
if (isStdlibInterface("Float32Array")) return bytesOf("f32");
|
||||
if (isStdlibInterface("Float64Array")) return bytesOf("f64");
|
||||
// DataView: the ONE view kind — a u8 bytes value whose runtime
|
||||
// representation borrows (aliases) its owner's storage, so reads through
|
||||
// it see writes to the source exactly like JS. The checker keeps the
|
||||
|
||||
@@ -24,11 +24,10 @@ export interface SrcLoc {
|
||||
|
||||
/* ── types ─────────────────────────────────────────────────────────────── */
|
||||
|
||||
/** The typed-array element kinds with a runtime representation: exactly
|
||||
* the constructors real CLI code reaches (Uint8Array/Buffer, Uint32Array,
|
||||
* Int32Array — the Atomics.wait sleep idiom's array — Float32Array). The
|
||||
* other TypedArray flavors stay frontend-fenced. */
|
||||
export type IrBytesElem = "u8" | "u32" | "i32" | "f32";
|
||||
/** Typed-array element kinds with a runtime representation: Uint8Array/Buffer,
|
||||
* Uint32Array, Int32Array, Float32Array, and Float64Array. Other flavors stay
|
||||
* frontend-fenced. */
|
||||
export type IrBytesElem = "u8" | "u32" | "i32" | "f32" | "f64";
|
||||
|
||||
export type IrType =
|
||||
| { kind: "f64" }
|
||||
@@ -72,14 +71,14 @@ export type IrType =
|
||||
* elements, no map keys/values, no union arms (a regex arm would have no
|
||||
* narrowing test), not JSON-safe. */
|
||||
| { kind: "regex" }
|
||||
/** A typed array / Node Buffer (Uint8Array, Uint32Array, Float32Array;
|
||||
/** A typed array / Node Buffer (Uint8Array, Uint32Array, Float32Array,
|
||||
* Float64Array;
|
||||
* Buffer IS a Uint8Array subclass and shares the u8 kind) — heap,
|
||||
* refcounted, MUTABLE, fixed-length, with ONE runtime representation
|
||||
* (ScrBytes) that OWNS its storage: no views exist — subarray()/slice()
|
||||
* both COPY (documented divergence for subarray), `.buffer`/
|
||||
* `.byteOffset`/DataView are frontend-fenced. Element reads widen to
|
||||
* f64; writes coerce JS-exactly (ToUint8/ToUint32 modular truncation,
|
||||
* double→float rounding). OOB element access traps like arrays. Allowed
|
||||
* (ScrBytes) that owns storage or borrows it for subarray and DataView
|
||||
* views. Typed-array slice copies. Element reads widen to f64; writes
|
||||
* coerce JS-exactly (ToUint8/ToUint32 modular truncation and f32
|
||||
* rounding). OOB element access traps like arrays. Allowed
|
||||
* as array elements and union arms (tag-based narrowing, like url);
|
||||
* fenced out of map keys/values, set elements, and JSON. Holds only raw
|
||||
* bytes — never part of a cycle, no trace. */
|
||||
|
||||
@@ -26,7 +26,7 @@ static void scr_bytes_oom(void) {
|
||||
}
|
||||
|
||||
size_t scr_bytes_elem_size(ScrBytesElem elem) {
|
||||
return elem == SCR_BYTES_U8 ? 1 : 4;
|
||||
return elem == SCR_BYTES_U8 ? 1 : elem == SCR_BYTES_F64 ? 8 : 4;
|
||||
}
|
||||
|
||||
/* ── lifecycle ─────────────────────────────────────────────────────────── */
|
||||
@@ -149,6 +149,11 @@ double scr_bytes_get(const ScrBytes *b, double i) {
|
||||
memcpy(&v, b->data + idx * 4, 4);
|
||||
return (double)v;
|
||||
}
|
||||
case SCR_BYTES_F64: {
|
||||
double v;
|
||||
memcpy(&v, b->data + idx * 8, 8);
|
||||
return v;
|
||||
}
|
||||
case SCR_BYTES_I32: {
|
||||
int32_t v;
|
||||
memcpy(&v, b->data + idx * 4, 4);
|
||||
@@ -174,6 +179,9 @@ void scr_bytes_set(ScrBytes *b, double i, double v) {
|
||||
memcpy(b->data + idx * 4, &f, 4);
|
||||
break;
|
||||
}
|
||||
case SCR_BYTES_F64:
|
||||
memcpy(b->data + idx * 8, &v, 8);
|
||||
break;
|
||||
case SCR_BYTES_I32: {
|
||||
/* ToInt32 is ToUint32 reinterpreted signed (same 2^32 residue). */
|
||||
uint32_t u = scr_bytes_to_u32(v);
|
||||
@@ -1605,6 +1613,9 @@ ScrBytes *scr_bytes_from_arr(ScrBytesElem elem, const ScrArr *arr) {
|
||||
memcpy(b->data + i * 4, &f, 4);
|
||||
break;
|
||||
}
|
||||
case SCR_BYTES_F64:
|
||||
memcpy(b->data + i * 8, &v, 8);
|
||||
break;
|
||||
case SCR_BYTES_I32: {
|
||||
uint32_t u = scr_bytes_to_u32(v);
|
||||
memcpy(b->data + i * 4, &u, 4); /* same residue reinterpreted */
|
||||
|
||||
@@ -9717,6 +9717,7 @@ ScrJsval *scr_jsval_from_bytes(const ScrBytes *b) {
|
||||
JSValue v = JS_NewTypedArray(isl_ctx, 3, argv,
|
||||
b->elem == SCR_BYTES_U32 ? JS_TYPED_ARRAY_UINT32
|
||||
: b->elem == SCR_BYTES_I32 ? JS_TYPED_ARRAY_INT32
|
||||
: b->elem == SCR_BYTES_F64 ? JS_TYPED_ARRAY_FLOAT64
|
||||
: JS_TYPED_ARRAY_FLOAT32);
|
||||
JS_FreeValue(isl_ctx, buf);
|
||||
if (JS_IsException(v)) {
|
||||
|
||||
@@ -5093,7 +5093,7 @@ double scr_bit_ushr(double a, double b);
|
||||
double scr_bit_not(double a);
|
||||
|
||||
/* ── typed arrays / Buffer (scr_bytes.c) ──────────────────────────────
|
||||
* ONE runtime representation for Uint8Array/Uint32Array/Float32Array,
|
||||
* ONE runtime representation for Uint8Array/Uint32Array/Float32Array/Float64Array,
|
||||
* Node's Buffer (a Uint8Array subclass), and DataView: a refcounted,
|
||||
* MUTABLE, fixed-length element buffer. An ScrBytes either OWNS its
|
||||
* storage (backing == NULL, byteOffset 0) or is a VIEW: its `data` points
|
||||
@@ -5119,6 +5119,7 @@ typedef enum ScrBytesElem {
|
||||
SCR_BYTES_U32, /* Uint32Array */
|
||||
SCR_BYTES_F32, /* Float32Array */
|
||||
SCR_BYTES_I32, /* Int32Array (reads sign-extend; writes ToInt32-wrap) */
|
||||
SCR_BYTES_F64, /* Float64Array */
|
||||
} ScrBytesElem;
|
||||
|
||||
typedef struct ScrBytes {
|
||||
@@ -5133,7 +5134,7 @@ typedef struct ScrBytes {
|
||||
struct ScrBytes *backing;
|
||||
} ScrBytes;
|
||||
|
||||
size_t scr_bytes_elem_size(ScrBytesElem elem); /* 1, 4, 4 */
|
||||
size_t scr_bytes_elem_size(ScrBytesElem elem); /* 1, 4, or 8 */
|
||||
|
||||
/* node:string_decoder's StringDecoder (scr_bytes.c, beside the decoders
|
||||
* it shares): the decoder value is a record holding the CANONICAL
|
||||
|
||||
@@ -0,0 +1,70 @@
|
||||
// Float64Array keeps double precision across construction, element access,
|
||||
// copies, views, DataView aliases, and typed-array methods.
|
||||
const a = new Float64Array(4);
|
||||
console.log("empty", a.length, a.byteLength, a.byteOffset, a[0], a[3]);
|
||||
a[0] = 0.1;
|
||||
a[1] = -0.25;
|
||||
a[2] = 1e100;
|
||||
a[3] = -0;
|
||||
console.log("elements", a[0], a[1], a[2], 1 / a[3]);
|
||||
|
||||
const seeded = new Float64Array([Math.PI, 0.1, -1.5]);
|
||||
console.log("seeded", seeded.length, seeded.byteLength, seeded[0], seeded[1], seeded[2]);
|
||||
const values = [0.2, -3.25];
|
||||
const fromArray = new Float64Array(values);
|
||||
console.log("from-array", fromArray[0], fromArray[1]);
|
||||
const copy = new Float64Array(seeded);
|
||||
copy[0] = 12.5;
|
||||
console.log("copy", seeded[0], copy[0]);
|
||||
|
||||
const bufferBacked = new Float64Array(new ArrayBuffer(16));
|
||||
bufferBacked[1] = 3.25;
|
||||
console.log("buffer", bufferBacked.length, bufferBacked.byteLength, bufferBacked[0], bufferBacked[1]);
|
||||
const view = new DataView(bufferBacked.buffer);
|
||||
view.setFloat64(0, -7.5, true);
|
||||
console.log("dataview", bufferBacked[0], view.getFloat64(8, true));
|
||||
const alias = Buffer.from(bufferBacked.buffer);
|
||||
alias.writeDoubleLE(4.5, 8);
|
||||
console.log("buffer-alias", alias.length, bufferBacked[1]);
|
||||
|
||||
const sub = a.subarray(1, 3);
|
||||
sub[0] = 6.75;
|
||||
console.log("subarray", a[1], sub[0], sub.length, sub.byteLength, sub.byteOffset);
|
||||
const slice = a.slice(1, 3);
|
||||
slice[0] = 9.5;
|
||||
console.log("slice", a[1], slice[0], slice.byteLength);
|
||||
|
||||
const filled = new Float64Array(4);
|
||||
filled.fill(0.1, 1, 3);
|
||||
filled.set(new Float64Array([5.5, 6.25]), 2);
|
||||
console.log("fill-set", filled[0], filled[1], filled[2], filled[3]);
|
||||
filled.subarray(0, 2).fill(-2.5);
|
||||
console.log("fill-view", filled[0], filled[1]);
|
||||
|
||||
const odd = new Float64Array([0 / 0, 1 / 0, -1 / 0, -0]);
|
||||
console.log("special", odd[0] !== odd[0], odd[1], odd[2], 1 / odd[3]);
|
||||
console.log("lengths", new Float64Array().length, new Float64Array(3.5).length, new Float64Array(0 / 0).length);
|
||||
|
||||
function doubleFirst(xs: Float64Array): Float64Array {
|
||||
const result = new Float64Array(xs);
|
||||
result[0] = xs[0] * 2;
|
||||
return result;
|
||||
}
|
||||
const doubled = doubleFirst(seeded);
|
||||
console.log("typed", doubled[0], seeded[0]);
|
||||
|
||||
const looped = new Float64Array(4);
|
||||
let sum = 0;
|
||||
for (let i = 0; i < looped.length; i++) {
|
||||
looped[i] = i + 0.125;
|
||||
sum += looped[i];
|
||||
}
|
||||
console.log("loop", sum, looped[0], looped[3]);
|
||||
|
||||
try {
|
||||
new Float64Array(-1);
|
||||
console.log("bad-length", "ok");
|
||||
} catch (e) {
|
||||
if (e instanceof RangeError) console.log("bad-length", e.name, e.message);
|
||||
else console.log("bad-length", "unexpected");
|
||||
}
|
||||
@@ -38,6 +38,9 @@ console.log(`${hw.length}`, `${hw[1]}`, `${hw.constructor.name}`);
|
||||
const floats = new Float32Array([1.5, -0.25]);
|
||||
const hf: any = floats;
|
||||
console.log(`${hf.length}`, `${hf[1]}`, `${hf.constructor.name}`);
|
||||
const doubles = new Float64Array([Math.PI, -0.1]);
|
||||
const hd: any = doubles;
|
||||
console.log(`${hd.length}`, `${hd[0]}`, `${hd[1]}`, `${hd.constructor.name}`);
|
||||
|
||||
// A bytes-armed union, both arms.
|
||||
function payload(flag: boolean): Uint8Array | string {
|
||||
|
||||
@@ -39,4 +39,4 @@ dataview.ts:13:29 - error SC2020: 'new DataView over this buffer expression' is
|
||||
| ^~
|
||||
14 | void view;
|
||||
|
||||
hint: views compile over a typed array's own storage — new DataView(x.buffer, byteOffset?, byteLength?) where x is a Uint8Array/Uint32Array/Float32Array/Buffer value — or a fresh buffer erased into the view: new DataView(new ArrayBuffer(n), ...); free-standing ArrayBuffers have no representation
|
||||
hint: views compile over a typed array's own storage — new DataView(x.buffer, byteOffset?, byteLength?) where x is a Uint8Array/Uint32Array/Float32Array/Float64Array/Buffer value — or a fresh buffer erased into the view: new DataView(new ArrayBuffer(n), ...); free-standing ArrayBuffers have no representation
|
||||
Reference in New Issue
Block a user