///
import { BLOCK, BLOCK_OVERHEAD, BLOCK_MAXSIZE } from "./rt/common";
import { idof } from "./builtins";
import { E_INDEXOUTOFRANGE, E_INVALIDLENGTH, E_HOLEYARRAY } from "./util/error";
// NOTE: DO NOT USE YET!
// TODO: FixedArray with S being the static size, i.e. `new FixedArray`.
// Then hard-wire this special type to the compiler and do static length checks instead :)
export class FixedArray {
[key: number]: T;
constructor(length: i32) {
if (length > BLOCK_MAXSIZE >>> alignof()) throw new RangeError(E_INVALIDLENGTH);
if (isReference()) {
if (!isNullable()) {
if (length) throw new Error(E_HOLEYARRAY);
}
}
var outSize = length << alignof();
var out = __alloc(outSize, idof>());
memory.fill(out, 0, outSize);
return changetype>(out); // retains
}
get length(): i32 {
return changetype(changetype(this) - BLOCK_OVERHEAD).rtSize >>> alignof();
}
@operator("[]") private __get(index: i32): T {
if (index >= this.length) throw new RangeError(E_INDEXOUTOFRANGE);
return this.__unchecked_get(index);
}
@operator("[]=") private __set(index: i32, value: T): void {
if (index >= this.length) throw new RangeError(E_INDEXOUTOFRANGE);
return this.__unchecked_set(index, value);
}
@operator("{}") private __unchecked_get(index: i32): T {
return load(changetype(this) + (index << alignof()));
}
@operator("{}=") private __unchecked_set(index: i32, value: T): void {
if (isManaged()) {
let offset = changetype(this) + (index << alignof());
let oldValue = load(offset);
if (changetype(value) != oldValue) {
store(offset, __retain(changetype(value)));
__release(changetype(oldValue));
}
} else {
store(changetype(this) + (index << alignof()), value);
}
}
// RT integration
@unsafe private __visit_impl(cookie: u32): void {
if (isManaged()) {
let cur = changetype(this);
let end = cur + changetype(changetype(this) - BLOCK_OVERHEAD).rtSize;
while (cur < end) {
let val = load(cur);
if (val) __visit(val, cookie);
cur += sizeof();
}
}
}
}