263 lines
6.9 KiB
TypeScript
Raw Normal View History

2017-12-16 17:54:53 +01:00
export class Array<T> {
private __memory: usize;
2018-01-14 21:17:43 +01:00
private __capacity: i32; // capped to [0, 0x7fffffff]
private __length: i32; // capped to [0, __capacity]
private __grow(newCapacity: i32): void {
assert(newCapacity > this.__capacity);
var newMemory = allocate_memory(<usize>newCapacity * sizeof<T>());
if (this.__memory) {
move_memory(newMemory, this.__memory, <usize>this.__capacity * sizeof<T>());
2018-01-14 21:17:43 +01:00
free_memory(this.__memory);
}
this.__memory = newMemory;
this.__capacity = newCapacity;
}
constructor(capacity: i32 = 0) {
2018-02-25 23:21:32 +01:00
if (capacity < 0) {
2018-01-14 21:17:43 +01:00
throw new RangeError("Invalid array length");
2018-02-25 23:21:32 +01:00
}
this.__memory = capacity
? allocate_memory(<usize>capacity * sizeof<T>())
: 0;
2018-01-14 21:17:43 +01:00
this.__capacity = this.__length = capacity;
}
get length(): i32 {
return this.__length;
}
set length(length: i32) {
2018-02-25 23:21:32 +01:00
if (length < 0) {
2018-01-14 21:17:43 +01:00
throw new RangeError("Invalid array length");
2018-02-25 23:21:32 +01:00
}
if (length > this.__capacity) {
2018-01-14 21:17:43 +01:00
this.__grow(max(length, this.__capacity << 1));
2018-02-25 23:21:32 +01:00
}
2018-01-14 21:17:43 +01:00
this.__length = length;
}
@operator("[]")
2018-01-06 10:20:38 +01:00
private __get(index: i32): T {
if (<u32>index >= <u32>this.__capacity) {
2018-01-14 21:17:43 +01:00
throw new Error("Index out of bounds"); // return changetype<T>(0) ?
2018-02-25 23:21:32 +01:00
}
return load<T>(this.__memory + <usize>index * sizeof<T>());
}
@operator("[]=")
2018-01-06 10:20:38 +01:00
private __set(index: i32, value: T): void {
2018-02-25 23:21:32 +01:00
if (index < 0) {
2018-01-14 21:17:43 +01:00
throw new Error("Index out of bounds");
2018-02-25 23:21:32 +01:00
}
if (index >= this.__capacity) {
2018-01-14 21:17:43 +01:00
this.__grow(max(index + 1, this.__capacity << 1));
2018-02-25 23:21:32 +01:00
}
store<T>(this.__memory + <usize>index * sizeof<T>(), value);
}
includes(searchElement: T, fromIndex: i32 = 0): bool {
if (this.__length == 0 || fromIndex >= this.__length) {
return false;
}
if (fromIndex < 0) {
fromIndex = this.__length + fromIndex;
if (fromIndex < 0) {
fromIndex = 0;
}
}
while (<u32>fromIndex < <u32>this.__length) {
if (load<T>(this.__memory + <usize>fromIndex * sizeof<T>()) == searchElement) {
return true;
}
++fromIndex;
}
return false;
}
indexOf(searchElement: T, fromIndex: i32 = 0): i32 {
if (this.__length == 0 || fromIndex >= this.__length) {
return -1;
}
2018-02-25 23:21:32 +01:00
if (fromIndex < 0) {
2018-01-14 21:17:43 +01:00
fromIndex = this.__length + fromIndex;
if (fromIndex < 0) {
fromIndex = 0;
}
2018-02-25 23:21:32 +01:00
}
while (<u32>fromIndex < <u32>this.__length) {
if (load<T>(this.__memory + <usize>fromIndex * sizeof<T>()) == searchElement) {
2018-01-14 21:17:43 +01:00
return fromIndex;
2018-02-25 23:21:32 +01:00
}
2018-01-14 21:17:43 +01:00
++fromIndex;
}
return -1;
}
lastIndexOf(searchElement: T, fromIndex: i32 = this.__length): i32 {
if (this.__length == 0) {
return -1;
}
2018-02-25 23:21:32 +01:00
if (fromIndex < 0) {
2018-01-14 21:17:43 +01:00
fromIndex = this.__length + fromIndex;
2018-02-25 23:21:32 +01:00
} else if (fromIndex >= this.__length) {
2018-01-14 21:17:43 +01:00
fromIndex = this.__length - 1;
2018-02-25 23:21:32 +01:00
}
2018-01-14 21:17:43 +01:00
while (fromIndex >= 0) {
if (load<T>(this.__memory + <usize>fromIndex * sizeof<T>()) == searchElement) {
2018-01-14 21:17:43 +01:00
return fromIndex;
2018-02-25 23:21:32 +01:00
}
2018-01-14 21:17:43 +01:00
--fromIndex;
}
2018-01-14 21:17:43 +01:00
return -1;
}
push(element: T): i32 {
2018-02-25 23:21:32 +01:00
if (this.__length == this.__capacity) {
2018-01-14 21:17:43 +01:00
this.__grow(this.__capacity ? this.__capacity << 1 : 1);
2018-02-25 23:21:32 +01:00
}
store<T>(this.__memory + <usize>this.__length * sizeof<T>(), element);
2018-01-14 21:17:43 +01:00
return ++this.__length;
}
pop(): T {
2018-02-25 23:21:32 +01:00
if (this.__length < 1) {
2018-01-14 21:17:43 +01:00
throw new RangeError("Array is empty"); // return changetype<T>(0) ?
2018-02-25 23:21:32 +01:00
}
return load<T>(this.__memory + <usize>--this.__length * sizeof<T>());
}
2017-12-16 02:27:39 +01:00
shift(): T {
2018-02-25 23:21:32 +01:00
if (this.__length < 1) {
2018-01-14 21:17:43 +01:00
throw new RangeError("Array is empty"); // return changetype<T>(0) ?
2018-02-25 23:21:32 +01:00
}
var element = load<T>(this.__memory);
2018-02-25 23:21:32 +01:00
move_memory(
this.__memory,
this.__memory + sizeof<T>(),
<usize>(this.__capacity - 1) * sizeof<T>()
2018-02-25 23:21:32 +01:00
);
set_memory(
this.__memory + <usize>(this.__capacity - 1) * sizeof<T>(),
2018-02-25 23:21:32 +01:00
0,
sizeof<T>()
);
2018-01-14 21:17:43 +01:00
--this.__length;
return element;
}
unshift(element: T): i32 {
var oldCapacity = this.__capacity;
2018-01-14 21:17:43 +01:00
if (this.__length == oldCapacity) {
// inlined __grow (avoids moving twice)
let newCapacity: i32 = oldCapacity ? oldCapacity << 1 : 1;
2018-01-14 02:41:13 +01:00
assert(newCapacity > this.__capacity);
let newMemory = allocate_memory(<usize>newCapacity * sizeof<T>());
2018-01-14 02:41:13 +01:00
if (this.__memory) {
2018-02-25 23:21:32 +01:00
move_memory(
newMemory + sizeof<T>(),
this.__memory,
<usize>oldCapacity * sizeof<T>()
2018-02-25 23:21:32 +01:00
);
2018-01-14 02:41:13 +01:00
free_memory(this.__memory);
}
this.__memory = newMemory;
this.__capacity = newCapacity;
2018-02-25 23:21:32 +01:00
} else {
move_memory(
this.__memory + sizeof<T>(),
this.__memory,
<usize>oldCapacity * sizeof<T>()
2018-02-25 23:21:32 +01:00
);
}
store<T>(this.__memory, element);
2018-01-14 21:17:43 +01:00
return ++this.__length;
}
slice(begin: i32 = 0, end: i32 = i32.MAX_VALUE): Array<T> {
if (begin < 0) {
begin = this.__length + begin;
2018-02-25 23:21:32 +01:00
if (begin < 0) {
2018-01-14 21:17:43 +01:00
begin = 0;
2018-02-25 23:21:32 +01:00
}
} else if (begin > this.__length) {
2018-01-14 21:17:43 +01:00
begin = this.__length;
2018-02-25 23:21:32 +01:00
}
if (end < 0) {
2018-01-14 21:17:43 +01:00
end = this.__length + end;
2018-02-25 23:21:32 +01:00
} else if (end > this.__length) {
2018-01-14 21:17:43 +01:00
end = this.__length;
2018-02-25 23:21:32 +01:00
}
if (end < begin) {
2018-01-14 21:17:43 +01:00
end = begin;
2018-02-25 23:21:32 +01:00
}
2018-01-14 21:17:43 +01:00
var capacity = end - begin;
assert(capacity >= 0);
var sliced = new Array<T>(capacity);
2018-02-25 23:21:32 +01:00
if (capacity) {
move_memory(
sliced.__memory,
this.__memory + <usize>begin * sizeof<T>(),
<usize>capacity * sizeof<T>()
);
}
2018-01-14 21:17:43 +01:00
return sliced;
}
splice(start: i32, deleteCount: i32 = i32.MAX_VALUE): void {
2018-02-25 23:21:32 +01:00
if (deleteCount < 1) {
2018-01-14 21:17:43 +01:00
return;
2018-02-25 23:21:32 +01:00
}
2018-01-14 21:17:43 +01:00
if (start < 0) {
start = this.__length + start;
2018-02-25 23:21:32 +01:00
if (start < 0) {
2018-01-14 21:17:43 +01:00
start = 0;
2018-02-25 23:21:32 +01:00
} else if (start >= this.__length) {
2018-01-14 21:17:43 +01:00
return;
2018-02-25 23:21:32 +01:00
}
} else if (start >= this.__length) {
2018-01-14 21:17:43 +01:00
return;
2018-02-25 23:21:32 +01:00
}
2018-01-14 21:17:43 +01:00
deleteCount = min(deleteCount, this.__length - start);
2018-02-25 23:21:32 +01:00
move_memory(
this.__memory + <usize>start * sizeof<T>(),
this.__memory + <usize>(start + deleteCount) * sizeof<T>(),
<usize>deleteCount * sizeof<T>()
2018-02-25 23:21:32 +01:00
);
2018-01-14 21:17:43 +01:00
this.__length -= deleteCount;
}
reverse(): Array<T> {
for (let front: usize = 0, back: usize = <usize>this.__length - 1; front < back; ++front, --back) {
let temp = load<T>(this.__memory + front * sizeof<T>());
2018-01-14 21:17:43 +01:00
store<T>(this.__memory + front * sizeof<T>(), load<T>(this.__memory + back * sizeof<T>()));
store<T>(this.__memory + back * sizeof<T>(), temp);
}
return this;
}
}
2018-01-05 01:55:59 +01:00
@unmanaged
2018-01-05 01:55:59 +01:00
export class CArray<T> {
private constructor() {}
@operator("[]")
private __get(index: i32): T {
2018-02-25 23:21:32 +01:00
if (index < 0) {
2018-01-14 21:17:43 +01:00
throw new RangeError("Index out of range");
2018-02-25 23:21:32 +01:00
}
return load<T>(changetype<usize>(this) + <usize>index * sizeof<T>());
2018-01-05 01:55:59 +01:00
}
@operator("[]=")
private __set(index: i32, value: T): void {
2018-02-25 23:21:32 +01:00
if (index < 0) {
2018-01-14 21:17:43 +01:00
throw new RangeError("Index out of range");
2018-02-25 23:21:32 +01:00
}
store<T>(changetype<usize>(this) + <usize>index * sizeof<T>(), value);
2018-01-05 01:55:59 +01:00
}
}