mirror of
https://github.com/fluencelabs/assemblyscript
synced 2025-05-01 18:02:15 +00:00
Implement Array#sort (#57)
This commit is contained in:
parent
37825fc84d
commit
c45a35b1c1
1
std/assembly.d.ts
vendored
1
std/assembly.d.ts
vendored
@ -304,6 +304,7 @@ declare class Array<T> {
|
|||||||
slice(from: i32, to?: i32): T[];
|
slice(from: i32, to?: i32): T[];
|
||||||
splice(start: i32, deleteCount?: i32): void;
|
splice(start: i32, deleteCount?: i32): void;
|
||||||
reverse(): T[];
|
reverse(): T[];
|
||||||
|
sort(comparator?: (a: T, b: T) => i32): T[];
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Class representing a C-like array of values of type `T` with limited capabilities. */
|
/** Class representing a C-like array of values of type `T` with limited capabilities. */
|
||||||
|
@ -1,3 +1,4 @@
|
|||||||
|
|
||||||
export class Array<T> {
|
export class Array<T> {
|
||||||
|
|
||||||
private __memory: usize;
|
private __memory: usize;
|
||||||
@ -287,6 +288,10 @@ export class Array<T> {
|
|||||||
}
|
}
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
sort(comparator: (a: T, b: T) => i32 = createDefaultComparator<T>()): Array<T> {
|
||||||
|
return sort<T>(this, comparator);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@unmanaged
|
@unmanaged
|
||||||
@ -311,3 +316,139 @@ export class CArray<T> {
|
|||||||
store<T>(changetype<usize>(this) + <usize>index * sizeof<T>(), value);
|
store<T>(changetype<usize>(this) + <usize>index * sizeof<T>(), value);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Internal methods
|
||||||
|
*/
|
||||||
|
|
||||||
|
// TODO remove this wrapper when indirect table landed
|
||||||
|
function createDefaultComparator<T>(): (a: T, b: T) => i32 {
|
||||||
|
return (a: T, b: T): i32 => (
|
||||||
|
<i32>(a > b) - <i32>(a < b)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
function insertionSort<T>(arr: Array<T>, comparator: (a: T, b: T) => i32): Array<T> {
|
||||||
|
var a: T, b: T, j: i32;
|
||||||
|
const typeShift = alignof<T>();
|
||||||
|
|
||||||
|
for (let i: i32 = 0, len: i32 = arr.length; i < len; i++) {
|
||||||
|
a = load<T>(arr.__memory + (i << typeShift)); // a = <T>arr[i];
|
||||||
|
j = i - 1;
|
||||||
|
while (j >= 0) {
|
||||||
|
b = load<T>(arr.__memory + (j << typeShift)); // b = <T>arr[j];
|
||||||
|
if (comparator(a, b) < 0) {
|
||||||
|
store<T>(arr.__memory + ((j + 1) << typeShift), b); // arr[j + 1] = b;
|
||||||
|
j--;
|
||||||
|
} else break;
|
||||||
|
}
|
||||||
|
|
||||||
|
store<T>(arr.__memory + ((j + 1) << typeShift), a); // arr[j + 1] = a;
|
||||||
|
}
|
||||||
|
|
||||||
|
return arr;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Weak Heap Sort implementation based on paper:
|
||||||
|
http://citeseerx.ist.psu.edu/viewdoc/download?doi=10.1.1.21.1863&rep=rep1&type=pdf
|
||||||
|
*/
|
||||||
|
function weakHeapSort<T>(arr: Array<T>, comparator: (a: T, b: T) => i32): Array<T> {
|
||||||
|
var len: i32 = arr.length;
|
||||||
|
var i: i32, j: i32, y: i32, p: i32, a: T, b: T;
|
||||||
|
|
||||||
|
const typeShift = alignof<T>();
|
||||||
|
const intShift = alignof<i32>();
|
||||||
|
|
||||||
|
var blen = (len + 7) >> 3;
|
||||||
|
var bitset = allocate_memory(blen << intShift);
|
||||||
|
|
||||||
|
set_memory(bitset, 0, blen << intShift);
|
||||||
|
|
||||||
|
for (i = len - 1; i > 0; i--) {
|
||||||
|
j = i;
|
||||||
|
while ((j & 1) == ((load<i32>(bitset + ((j >> 4) << intShift)) >> ((j >> 1) & 7)) & 1)) {
|
||||||
|
j >>= 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
p = j >> 1;
|
||||||
|
|
||||||
|
a = load<T>(arr.__memory + (p << typeShift)); // a = <T>arr[p];
|
||||||
|
b = load<T>(arr.__memory + (i << typeShift)); // b = <T>arr[i];
|
||||||
|
|
||||||
|
if (comparator(a, b) < 0) {
|
||||||
|
store<i32>(
|
||||||
|
bitset + ((i >> 3) << intShift),
|
||||||
|
load<i32>(bitset + ((i >> 3) << intShift)) ^ (1 << (i & 7))
|
||||||
|
);
|
||||||
|
store<T>(arr.__memory + (i << typeShift), a); // arr[i] = a;
|
||||||
|
store<T>(arr.__memory + (p << typeShift), b); // arr[p] = b;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (i = len - 1; i >= 2; i--) {
|
||||||
|
/*
|
||||||
|
a = <T>arr[0];
|
||||||
|
arr[0] = <T>arr[i];
|
||||||
|
arr[i] = a;
|
||||||
|
*/
|
||||||
|
a = load<T>(arr.__memory, 0);
|
||||||
|
store<T>(arr.__memory, load<T>(arr.__memory + (i << typeShift)), 0);
|
||||||
|
store<T>(arr.__memory + (i << typeShift), a);
|
||||||
|
|
||||||
|
let x = 1;
|
||||||
|
while ((y = (x << 1) + ((load<i32>(bitset + ((x >> 3) << intShift)) >> (x & 7)) & 1)) < i) {
|
||||||
|
x = y;
|
||||||
|
}
|
||||||
|
|
||||||
|
while (x > 0) {
|
||||||
|
a = load<T>(arr.__memory, 0); // a = <T>arr[0];
|
||||||
|
b = load<T>(arr.__memory + (x << typeShift)); // b = <T>arr[x];
|
||||||
|
|
||||||
|
if (comparator(a, b) < 0) {
|
||||||
|
store<i32>(
|
||||||
|
bitset + ((x >> 3) << intShift),
|
||||||
|
load<i32>(bitset + ((x >> 3) << intShift)) ^ (1 << (x & 7))
|
||||||
|
);
|
||||||
|
|
||||||
|
store<T>(arr.__memory + (x << typeShift), a); // arr[x] = a;
|
||||||
|
store<T>(arr.__memory, b, 0); // arr[0] = b;
|
||||||
|
}
|
||||||
|
x >>= 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
free_memory(bitset);
|
||||||
|
|
||||||
|
/*
|
||||||
|
let t = <T>arr[1];
|
||||||
|
arr[1] = <T>arr[0];
|
||||||
|
arr[0] = t;
|
||||||
|
*/
|
||||||
|
var t = load<T>(arr.__memory, sizeof<T>());
|
||||||
|
store<T>(arr.__memory, load<T>(arr.__memory, 0), sizeof<T>());
|
||||||
|
store<T>(arr.__memory, t, 0);
|
||||||
|
|
||||||
|
return arr;
|
||||||
|
}
|
||||||
|
|
||||||
|
function sort<T>(arr: Array<T>, comparator: (a: T, b: T) => i32): Array<T> {
|
||||||
|
var len = arr.length;
|
||||||
|
|
||||||
|
if (len <= 1) return arr;
|
||||||
|
|
||||||
|
if (len == 2) {
|
||||||
|
let a = load<T>(arr.__memory, sizeof<T>()); // var a = <T>arr[1];
|
||||||
|
let b = load<T>(arr.__memory, 0); // var b = <T>arr[0];
|
||||||
|
if (comparator(a, b) < 0) {
|
||||||
|
store<T>(arr.__memory, b, sizeof<T>()); // arr[1] = b;
|
||||||
|
store<T>(arr.__memory, a, 0); // arr[0] = a;
|
||||||
|
}
|
||||||
|
return arr;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (len <= 256) {
|
||||||
|
return insertionSort<T>(arr, comparator);
|
||||||
|
}
|
||||||
|
|
||||||
|
return weakHeapSort<T>(arr, comparator);
|
||||||
|
}
|
||||||
|
1
std/portable.d.ts
vendored
1
std/portable.d.ts
vendored
@ -232,6 +232,7 @@ declare class Array<T> {
|
|||||||
slice(from: i32, to?: i32): T[];
|
slice(from: i32, to?: i32): T[];
|
||||||
splice(start: i32, deleteCount?: i32): void;
|
splice(start: i32, deleteCount?: i32): void;
|
||||||
reverse(): T[];
|
reverse(): T[];
|
||||||
|
sort(comparator?: (a: T, b: T) => i32): T[];
|
||||||
|
|
||||||
join(delim: string): string;
|
join(delim: string): string;
|
||||||
}
|
}
|
||||||
|
File diff suppressed because it is too large
Load Diff
@ -1,5 +1,86 @@
|
|||||||
import "allocator/arena";
|
import "allocator/arena";
|
||||||
|
|
||||||
|
// Default comparator
|
||||||
|
function createDefaultComparator<T>(): (a: T, b: T) => i32 {
|
||||||
|
return (a: T, b: T): i32 => (
|
||||||
|
<i32>(a > b) - <i32>(a < b)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check is array sorted
|
||||||
|
function isSorted<T>(data: Array<T>, comparator: (a: T, b: T) => i32 = createDefaultComparator<T>()): bool {
|
||||||
|
for (let i: i32 = 1, len: i32 = data.length; i < len; i++) {
|
||||||
|
if (comparator(data[i - 1], data[i]) > 0) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check is equality for arrays
|
||||||
|
function isArraysEqual<T>(a: Array<T>, b: Array<T>, maxLen: i32 = 0): bool {
|
||||||
|
var len = maxLen;
|
||||||
|
if (!maxLen) {
|
||||||
|
if (a.length != b.length) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
len = <i32>a.length;
|
||||||
|
}
|
||||||
|
for (let i: i32 = 0; i < len; i++) {
|
||||||
|
if (a[i] != b[i]) return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
function createReverseOrderedArray(size: i32): Array<i32> {
|
||||||
|
var arr = new Array<i32>(size);
|
||||||
|
for (let i: i32 = 0; i < arr.length; i++) {
|
||||||
|
arr[i] = <i32>arr.length - 1 - i;
|
||||||
|
}
|
||||||
|
return arr;
|
||||||
|
}
|
||||||
|
|
||||||
|
NativeMath.seedRandom(reinterpret<u64>(JSMath.random()));
|
||||||
|
|
||||||
|
function createRandomOrderedArray(size: i32): Array<i32> {
|
||||||
|
var arr = new Array<i32>(size);
|
||||||
|
for (let i: i32 = 0; i < arr.length; i++) {
|
||||||
|
arr[i] = <i32>(NativeMath.random() * arr.length);
|
||||||
|
}
|
||||||
|
return arr;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
function createReverseOrderedNestedArray(size: i32): Array<Array<i32>> {
|
||||||
|
var arr = new Array<Array<i32>>(size);
|
||||||
|
for (let i: i32 = 0; i < arr.length; i++) {
|
||||||
|
arr[i] = new Array<i32>(1);
|
||||||
|
arr[i][0] = arr.length - 1 - i;
|
||||||
|
}
|
||||||
|
return arr;
|
||||||
|
}
|
||||||
|
|
||||||
|
class Proxy<T> {
|
||||||
|
constructor(public x: T) {}
|
||||||
|
}
|
||||||
|
|
||||||
|
function createReverseOrderedElementsArray(size: i32): Proxy<i32>[] {
|
||||||
|
var arr = new Array<Proxy<i32>>(size);
|
||||||
|
for (let i: i32 = 0; i < arr.length; i++) {
|
||||||
|
arr[i] = new Proxy<i32>(arr.length - 1 - i);
|
||||||
|
}
|
||||||
|
return arr;
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
|
function assertSorted<T>(arr: Array<T>, comparator: (a: T, b: T) => i32): void {
|
||||||
|
assert(isSorted<T>(arr.sort<T>(comparator), comparator));
|
||||||
|
}
|
||||||
|
|
||||||
|
function assertSortedDefault<T>(arr: Array<T>): void {
|
||||||
|
assertSorted<T>(arr, createDefaultComparator<T>());
|
||||||
|
}
|
||||||
|
|
||||||
var arr = changetype<i32[]>(allocate_memory(sizeof<usize>() + 2 * sizeof<i32>()));
|
var arr = changetype<i32[]>(allocate_memory(sizeof<usize>() + 2 * sizeof<i32>()));
|
||||||
|
|
||||||
assert(arr.length == 0);
|
assert(arr.length == 0);
|
||||||
@ -323,3 +404,66 @@ i = arr.reduce<i32>(((prev: i32, current: i32, index: i32, array: Array<i32>): i
|
|||||||
// only 2 first items was reduced, since last 2 was removed by .pop()
|
// only 2 first items was reduced, since last 2 was removed by .pop()
|
||||||
assert(i == 1);
|
assert(i == 1);
|
||||||
assert(arr.length == 2);
|
assert(arr.length == 2);
|
||||||
|
|
||||||
|
/*=============================== sort ==========================*/
|
||||||
|
|
||||||
|
var revesed0: Array<i32> = [];
|
||||||
|
var revesed1: Array<i32> = [1];
|
||||||
|
var revesed2: Array<i32> = [2, 1];
|
||||||
|
var revesed4: Array<i32> = [3, 2, 1, 0];
|
||||||
|
|
||||||
|
var expected4: Array<i32> = [0, 1, 2, 3];
|
||||||
|
|
||||||
|
var revesed64 = createReverseOrderedArray(64);
|
||||||
|
var revesed128 = createReverseOrderedArray(128);
|
||||||
|
var revesed1024 = createReverseOrderedArray(1024);
|
||||||
|
var revesed10000 = createReverseOrderedArray(10000);
|
||||||
|
|
||||||
|
var randomized512 = createRandomOrderedArray(512);
|
||||||
|
|
||||||
|
// Test sorting with with default comparator
|
||||||
|
|
||||||
|
assertSortedDefault<i32>(revesed0);
|
||||||
|
|
||||||
|
assertSortedDefault<i32>(revesed1);
|
||||||
|
assert(isArraysEqual<i32>(revesed1, <i32[]>[1]));
|
||||||
|
|
||||||
|
assertSortedDefault<i32>(revesed2);
|
||||||
|
assert(isArraysEqual<i32>(revesed2, <i32[]>[1, 2]));
|
||||||
|
|
||||||
|
assertSortedDefault<i32>(revesed4);
|
||||||
|
assert(isArraysEqual<i32>(revesed4, expected4));
|
||||||
|
|
||||||
|
assertSortedDefault<i32>(revesed64);
|
||||||
|
assert(isArraysEqual<i32>(revesed64, expected4, 4));
|
||||||
|
|
||||||
|
assertSortedDefault<i32>(revesed128);
|
||||||
|
assert(isArraysEqual<i32>(revesed128, expected4, 4));
|
||||||
|
|
||||||
|
assertSortedDefault<i32>(revesed1024);
|
||||||
|
assert(isArraysEqual<i32>(revesed1024, expected4, 4));
|
||||||
|
|
||||||
|
assertSortedDefault<i32>(revesed10000);
|
||||||
|
assert(isArraysEqual<i32>(revesed10000, expected4, 4));
|
||||||
|
|
||||||
|
assertSortedDefault<i32>(randomized512);
|
||||||
|
|
||||||
|
// Test sorting with custom comparator
|
||||||
|
|
||||||
|
var randomized64 = createRandomOrderedArray(64);
|
||||||
|
var randomized257 = createRandomOrderedArray(257);
|
||||||
|
|
||||||
|
assertSorted<i32>(randomized64, (a: i32, b: i32): i32 => a - b);
|
||||||
|
assertSorted<i32>(randomized64, (a: i32, b: i32): i32 => b - a);
|
||||||
|
|
||||||
|
assertSorted<i32>(randomized257, (a: i32, b: i32): i32 => a - b);
|
||||||
|
assertSorted<i32>(randomized257, (a: i32, b: i32): i32 => b - a);
|
||||||
|
|
||||||
|
// Test sorting complex objects
|
||||||
|
|
||||||
|
// var reversedNested512 = createReverseOrderedNestedArray(512);
|
||||||
|
// assertSorted<i32[]>(reversedNested512, (a: i32[], b: i32[]): i32 => a[0] - b[0]);
|
||||||
|
|
||||||
|
// Test sorting reference elements
|
||||||
|
// var reversedElements512 = createReverseOrderedElementsArray(512);
|
||||||
|
// assertSorted<Proxy<i32>>(reversedElements512, (a: Proxy<i32>, b: Proxy<i32>): i32 => a.x - b.x);
|
||||||
|
File diff suppressed because it is too large
Load Diff
@ -2024,7 +2024,7 @@
|
|||||||
(call $abort
|
(call $abort
|
||||||
(i32.const 0)
|
(i32.const 0)
|
||||||
(i32.const 160)
|
(i32.const 160)
|
||||||
(i32.const 8)
|
(i32.const 9)
|
||||||
(i32.const 4)
|
(i32.const 4)
|
||||||
)
|
)
|
||||||
(unreachable)
|
(unreachable)
|
||||||
@ -2160,7 +2160,7 @@
|
|||||||
(call $abort
|
(call $abort
|
||||||
(i32.const 0)
|
(i32.const 0)
|
||||||
(i32.const 160)
|
(i32.const 160)
|
||||||
(i32.const 8)
|
(i32.const 9)
|
||||||
(i32.const 4)
|
(i32.const 4)
|
||||||
)
|
)
|
||||||
(unreachable)
|
(unreachable)
|
||||||
|
@ -2322,7 +2322,7 @@
|
|||||||
(call $abort
|
(call $abort
|
||||||
(i32.const 0)
|
(i32.const 0)
|
||||||
(i32.const 160)
|
(i32.const 160)
|
||||||
(i32.const 8)
|
(i32.const 9)
|
||||||
(i32.const 4)
|
(i32.const 4)
|
||||||
)
|
)
|
||||||
(unreachable)
|
(unreachable)
|
||||||
@ -2469,7 +2469,7 @@
|
|||||||
(call $abort
|
(call $abort
|
||||||
(i32.const 0)
|
(i32.const 0)
|
||||||
(i32.const 160)
|
(i32.const 160)
|
||||||
(i32.const 8)
|
(i32.const 9)
|
||||||
(i32.const 4)
|
(i32.const 4)
|
||||||
)
|
)
|
||||||
(unreachable)
|
(unreachable)
|
||||||
@ -2616,7 +2616,7 @@
|
|||||||
(call $abort
|
(call $abort
|
||||||
(i32.const 0)
|
(i32.const 0)
|
||||||
(i32.const 160)
|
(i32.const 160)
|
||||||
(i32.const 8)
|
(i32.const 9)
|
||||||
(i32.const 4)
|
(i32.const 4)
|
||||||
)
|
)
|
||||||
(unreachable)
|
(unreachable)
|
||||||
@ -2763,7 +2763,7 @@
|
|||||||
(call $abort
|
(call $abort
|
||||||
(i32.const 0)
|
(i32.const 0)
|
||||||
(i32.const 160)
|
(i32.const 160)
|
||||||
(i32.const 8)
|
(i32.const 9)
|
||||||
(i32.const 4)
|
(i32.const 4)
|
||||||
)
|
)
|
||||||
(unreachable)
|
(unreachable)
|
||||||
|
Loading…
x
Reference in New Issue
Block a user