export class Array { private __memory: usize; private __capacity: i32; length: i32; constructor(capacity: i32 = 0) { if (capacity < 0) throw new RangeError("invalid array length"); this.__capacity = this.length = capacity; this.__memory = capacity > 0 ? allocate_memory(capacity * sizeof()) : 0; } @operator("[]") private __get(index: i32): T { if (index >= this.__capacity) throw new RangeError("index out of range"); return load(this.__memory + index * sizeof()); } @operator("[]=") private __set(index: i32, value: T): void { if (index >= this.__capacity) throw new RangeError("index out of range"); store(this.__memory + index * sizeof(), value); } indexOf(searchElement: T, fromIndex: i32 = 0): i32 { if (fromIndex >= this.__capacity) throw new RangeError("fromIndex out of range"); for (var index: usize = fromIndex, length: usize = min(this.length, this.__capacity); index < length; ++index) if (load(this.__memory + index * sizeof()) == searchElement) return index; return -1; } private __grow(newCapacity: i32): void { assert(newCapacity > this.__capacity); var newMemory = allocate_memory(newCapacity * sizeof()); if (this.__memory) { move_memory(newMemory, this.__memory, this.__capacity * sizeof()); free_memory(this.__memory); } this.__memory = newMemory; this.__capacity = newCapacity; } push(element: T): i32 { if (this.length >= this.__capacity) this.__grow(max(this.length + 1, this.__capacity << 1)); store(this.__memory + this.length * sizeof(), element); return ++this.length; } pop(): T { if (this.length < 1 || this.length > this.__capacity) throw new RangeError("index out of range"); --this.length; return load(this.__memory + this.length * sizeof()); } shift(): T { if (this.length < 1 || this.length > this.__capacity) throw new RangeError("index out of range"); var element = load(this.__memory); move_memory(this.__memory, this.__memory + sizeof(), (this.__capacity - 1) * sizeof()); set_memory(this.__memory + (this.__capacity - 1) * sizeof(), 0, sizeof()); --this.length; return element; } unshift(element: T): i32 { var oldCapacity = this.__capacity; if (this.length >= oldCapacity) this.__grow(max(this.length + 1, oldCapacity * 2)); // FIXME: this is inefficient because of two copies, one in __grow and one here // move_memory(this.__memory + sizeof(), this.__memory, oldCapacity * sizeof()); if (oldCapacity) for (var index: usize = oldCapacity; index > 0; --index) store(this.__memory + index * sizeof(), load(this.__memory + (index - 1) * sizeof())); store(this.__memory, element); return ++this.length; } } @explicit export class CArray { private constructor() {} @operator("[]") private __get(index: i32): T { if (index < 0) throw new RangeError("index out of range"); return load(changetype(this) + index * sizeof()); } @operator("[]=") private __set(index: i32, value: T): void { if (index < 0) throw new RangeError("index out of range"); store(changetype(this) + index * sizeof(), value); } }