mirror of
https://github.com/fluencelabs/assemblyscript
synced 2025-04-25 15:12:12 +00:00
Use insertion sort for references in Array#sort (#90)
This fixes that Weak Heap Sort isn't stable and thus might swap equal values, which sometimes results in not deep equal arrays of strings, for example. Insertion sort is stable, so it is used for references instead.
This commit is contained in:
parent
8b5d1d7f74
commit
99bde3a5fa
@ -314,9 +314,15 @@ export class Array<T> {
|
||||
}
|
||||
return this;
|
||||
}
|
||||
return changetype<this>(length < 256
|
||||
? insertionSort<T,T>(this, comparator)
|
||||
: weakHeapSort<T,T>(this, comparator)
|
||||
);
|
||||
|
||||
if (isReference<T>()) {
|
||||
// TODO replace this to stable sort when it implemented
|
||||
return changetype<this>(insertionSort<T>(this, comparator));
|
||||
} else {
|
||||
return changetype<this>(length < 256
|
||||
? insertionSort<T>(this, comparator)
|
||||
: weakHeapSort<T>(this, comparator)
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -14,25 +14,25 @@ export function defaultComparator<T>(): (a: T, b: T) => i32 {
|
||||
}
|
||||
|
||||
/** Sorts an Array with the 'Insertion Sort' algorithm. */
|
||||
export function insertionSort<T,V>(arr: Array<T>, comparator: (a: V, b: V) => i32): Array<T> {
|
||||
export function insertionSort<T>(arr: Array<T>, comparator: (a: T, b: T) => i32): Array<T> {
|
||||
var buffer = arr.buffer_;
|
||||
for (let i: i32 = 0, length: i32 = arr.length; i < length; i++) {
|
||||
let a = loadUnsafe<T,V>(buffer, i); // a = arr[i]
|
||||
let a = loadUnsafe<T,T>(buffer, i); // a = arr[i]
|
||||
let j = i - 1;
|
||||
while (j >= 0) {
|
||||
let b = loadUnsafe<T,V>(buffer, j); // b = arr[j]
|
||||
let b = loadUnsafe<T,T>(buffer, j); // b = arr[j]
|
||||
if (comparator(a, b) < 0) {
|
||||
storeUnsafe<T,V>(buffer, j-- + 1, b); // arr[j + 1] = b
|
||||
storeUnsafe<T,T>(buffer, j-- + 1, b); // arr[j + 1] = b
|
||||
} else break;
|
||||
}
|
||||
storeUnsafe<T,V>(buffer, j + 1, a); // arr[j + 1] = a
|
||||
storeUnsafe<T,T>(buffer, j + 1, a); // arr[j + 1] = a
|
||||
}
|
||||
return arr;
|
||||
}
|
||||
|
||||
/** Sorts an Array with the 'Weak Heap Sort' algorithm. */
|
||||
export function weakHeapSort<T,V>(arr: Array<T>, comparator: (a: V, b: V) => i32): Array<T> {
|
||||
const shift32 = alignof<i32>();
|
||||
export function weakHeapSort<T>(arr: Array<T>, comparator: (a: T, b: T) => i32): Array<T> {
|
||||
const shift32 = alignof<u32>();
|
||||
|
||||
var length = arr.length;
|
||||
var bitsetSize = (length + 31) >> 5 << shift32;
|
||||
@ -44,40 +44,40 @@ export function weakHeapSort<T,V>(arr: Array<T>, comparator: (a: V, b: V) => i32
|
||||
var buffer = arr.buffer_;
|
||||
for (let i = length - 1; i > 0; i--) {
|
||||
let j = i;
|
||||
while ((j & 1) == (load<i32>(bitset + (j >> 6 << shift32)) >> (j >> 1 & 31) & 1)) j >>= 1;
|
||||
while ((j & 1) == (load<u32>(bitset + (j >> 6 << shift32)) >> (j >> 1 & 31) & 1)) j >>= 1;
|
||||
|
||||
let p = j >> 1;
|
||||
let a = loadUnsafe<T,V>(buffer, p); // a = arr[p]
|
||||
let b = loadUnsafe<T,V>(buffer, i); // b = arr[i]
|
||||
let a = loadUnsafe<T,T>(buffer, p); // a = arr[p]
|
||||
let b = loadUnsafe<T,T>(buffer, i); // b = arr[i]
|
||||
if (comparator(a, b) < 0) {
|
||||
store<i32>(
|
||||
store<u32>(
|
||||
bitset + (i >> 5 << shift32),
|
||||
load<i32>(bitset + (i >> 5 << shift32)) ^ (1 << (i & 31))
|
||||
load<u32>(bitset + (i >> 5 << shift32)) ^ (1 << (i & 31))
|
||||
);
|
||||
storeUnsafe<T,V>(buffer, i, a); // arr[i] = a
|
||||
storeUnsafe<T,V>(buffer, p, b); // arr[p] = b
|
||||
storeUnsafe<T,T>(buffer, i, a); // arr[i] = a
|
||||
storeUnsafe<T,T>(buffer, p, b); // arr[p] = b
|
||||
}
|
||||
}
|
||||
|
||||
for (let i = length - 1; i >= 2; i--) {
|
||||
let a = loadUnsafe<T,V>(buffer, 0); // a = arr[0]
|
||||
storeUnsafe<T,V>(buffer, 0, loadUnsafe<T,V>(buffer, i)); // arr[0] = arr[i]
|
||||
storeUnsafe<T,V>(buffer, i, a); // arr[i] = a
|
||||
let a = loadUnsafe<T,T>(buffer, 0); // a = arr[0]
|
||||
storeUnsafe<T,T>(buffer, 0, loadUnsafe<T,T>(buffer, i)); // arr[0] = arr[i]
|
||||
storeUnsafe<T,T>(buffer, i, a); // arr[i] = a
|
||||
|
||||
let x = 1, y: i32;
|
||||
while ((y = (x << 1) + ((load<i32>(bitset + (x >> 5 << shift32)) >> (x & 31)) & 1)) < i) x = y;
|
||||
while ((y = (x << 1) + ((load<u32>(bitset + (x >> 5 << shift32)) >> (x & 31)) & 1)) < i) x = y;
|
||||
|
||||
while (x > 0) {
|
||||
a = loadUnsafe<T,V>(buffer, 0); // a = arr[0]
|
||||
let b = loadUnsafe<T,V>(buffer, x); // b = arr[x]
|
||||
a = loadUnsafe<T,T>(buffer, 0); // a = arr[0]
|
||||
let b = loadUnsafe<T,T>(buffer, x); // b = arr[x]
|
||||
|
||||
if (comparator(a, b) < 0) {
|
||||
store<i32>(
|
||||
store<u32>(
|
||||
bitset + (x >> 5 << shift32),
|
||||
load<i32>(bitset + (x >> 5 << shift32)) ^ (1 << (x & 31))
|
||||
load<u32>(bitset + (x >> 5 << shift32)) ^ (1 << (x & 31))
|
||||
);
|
||||
storeUnsafe<T,V>(buffer, x, a); // arr[x] = a
|
||||
storeUnsafe<T,V>(buffer, 0, b); // arr[0] = b
|
||||
storeUnsafe<T,T>(buffer, x, a); // arr[x] = a
|
||||
storeUnsafe<T,T>(buffer, 0, b); // arr[0] = b
|
||||
}
|
||||
x >>= 1;
|
||||
}
|
||||
@ -85,8 +85,8 @@ export function weakHeapSort<T,V>(arr: Array<T>, comparator: (a: V, b: V) => i32
|
||||
|
||||
free_memory(bitset);
|
||||
|
||||
var t = loadUnsafe<T,V>(buffer, 1); // t = arr[1]
|
||||
storeUnsafe<T,V>(buffer, 1, loadUnsafe<T,V>(buffer, 0)); // arr[1] = arr[0]
|
||||
storeUnsafe<T,V>(buffer, 0, t); // arr[0] = t
|
||||
var t = loadUnsafe<T,T>(buffer, 1); // t = arr[1]
|
||||
storeUnsafe<T,T>(buffer, 1, loadUnsafe<T,T>(buffer, 0)); // arr[1] = arr[0]
|
||||
storeUnsafe<T,T>(buffer, 0, t); // arr[0] = t
|
||||
return arr;
|
||||
}
|
||||
|
@ -4645,7 +4645,7 @@
|
||||
)
|
||||
)
|
||||
)
|
||||
(func $~lib/internal/array/insertionSort<i32,i32> (; 72 ;) (type $iii) (param $0 i32) (param $1 i32) (result i32)
|
||||
(func $~lib/internal/array/insertionSort<i32> (; 72 ;) (type $iii) (param $0 i32) (param $1 i32) (result i32)
|
||||
(local $2 i32)
|
||||
(local $3 i32)
|
||||
(local $4 i32)
|
||||
@ -4773,7 +4773,7 @@
|
||||
(func $~lib/allocator/arena/free_memory (; 73 ;) (type $iv) (param $0 i32)
|
||||
(nop)
|
||||
)
|
||||
(func $~lib/internal/array/weakHeapSort<i32,i32> (; 74 ;) (type $iii) (param $0 i32) (param $1 i32) (result i32)
|
||||
(func $~lib/internal/array/weakHeapSort<i32> (; 74 ;) (type $iii) (param $0 i32) (param $1 i32) (result i32)
|
||||
(local $2 i32)
|
||||
(local $3 i32)
|
||||
(local $4 i32)
|
||||
@ -4834,7 +4834,7 @@
|
||||
(i32.const 1)
|
||||
)
|
||||
(i32.and
|
||||
(i32.shr_s
|
||||
(i32.shr_u
|
||||
(i32.load
|
||||
(i32.add
|
||||
(get_local $6)
|
||||
@ -5029,7 +5029,7 @@
|
||||
(i32.const 1)
|
||||
)
|
||||
(i32.and
|
||||
(i32.shr_s
|
||||
(i32.shr_u
|
||||
(i32.load
|
||||
(i32.add
|
||||
(get_local $6)
|
||||
@ -5273,11 +5273,11 @@
|
||||
(get_local $2)
|
||||
(i32.const 256)
|
||||
)
|
||||
(call $~lib/internal/array/insertionSort<i32,i32>
|
||||
(call $~lib/internal/array/insertionSort<i32>
|
||||
(get_local $0)
|
||||
(get_local $1)
|
||||
)
|
||||
(call $~lib/internal/array/weakHeapSort<i32,i32>
|
||||
(call $~lib/internal/array/weakHeapSort<i32>
|
||||
(get_local $0)
|
||||
(get_local $1)
|
||||
)
|
||||
@ -5532,7 +5532,108 @@
|
||||
)
|
||||
)
|
||||
)
|
||||
(func $std/array/Proxy<i32>#constructor (; 85 ;) (type $iii) (param $0 i32) (param $1 i32) (result i32)
|
||||
(func $~lib/array/Array<Array<i32>>#sort (; 85 ;) (type $iii) (param $0 i32) (param $1 i32) (result i32)
|
||||
(local $2 i32)
|
||||
(local $3 i32)
|
||||
(local $4 i32)
|
||||
(if
|
||||
(i32.le_s
|
||||
(tee_local $2
|
||||
(i32.load offset=4
|
||||
(get_local $0)
|
||||
)
|
||||
)
|
||||
(i32.const 1)
|
||||
)
|
||||
(return
|
||||
(get_local $0)
|
||||
)
|
||||
)
|
||||
(set_local $3
|
||||
(i32.load
|
||||
(get_local $0)
|
||||
)
|
||||
)
|
||||
(if
|
||||
(i32.eq
|
||||
(get_local $2)
|
||||
(i32.const 2)
|
||||
)
|
||||
(block
|
||||
(set_local $2
|
||||
(i32.load offset=8
|
||||
(i32.add
|
||||
(get_local $3)
|
||||
(i32.const 4)
|
||||
)
|
||||
)
|
||||
)
|
||||
(set_local $4
|
||||
(i32.load offset=8
|
||||
(get_local $3)
|
||||
)
|
||||
)
|
||||
(if
|
||||
(block (result i32)
|
||||
(set_global $~argc
|
||||
(i32.const 2)
|
||||
)
|
||||
(i32.lt_s
|
||||
(call_indirect (type $iii)
|
||||
(get_local $2)
|
||||
(get_local $4)
|
||||
(get_local $1)
|
||||
)
|
||||
(i32.const 0)
|
||||
)
|
||||
)
|
||||
(block
|
||||
(i32.store offset=8
|
||||
(i32.add
|
||||
(get_local $3)
|
||||
(i32.const 4)
|
||||
)
|
||||
(get_local $4)
|
||||
)
|
||||
(i32.store offset=8
|
||||
(get_local $3)
|
||||
(get_local $2)
|
||||
)
|
||||
)
|
||||
)
|
||||
(return
|
||||
(get_local $0)
|
||||
)
|
||||
)
|
||||
)
|
||||
(call $~lib/internal/array/insertionSort<i32>
|
||||
(get_local $0)
|
||||
(get_local $1)
|
||||
)
|
||||
)
|
||||
(func $std/array/assertSorted<Array<i32>> (; 86 ;) (type $iiv) (param $0 i32) (param $1 i32)
|
||||
(if
|
||||
(i32.eqz
|
||||
(call $std/array/isSorted<i32>
|
||||
(call $~lib/array/Array<Array<i32>>#sort
|
||||
(get_local $0)
|
||||
(get_local $1)
|
||||
)
|
||||
(get_local $1)
|
||||
)
|
||||
)
|
||||
(block
|
||||
(call $abort
|
||||
(i32.const 0)
|
||||
(i32.const 96)
|
||||
(i32.const 605)
|
||||
(i32.const 2)
|
||||
)
|
||||
(unreachable)
|
||||
)
|
||||
)
|
||||
)
|
||||
(func $std/array/Proxy<i32>#constructor (; 87 ;) (type $iii) (param $0 i32) (param $1 i32) (result i32)
|
||||
(local $2 i32)
|
||||
(if (result i32)
|
||||
(get_local $0)
|
||||
@ -5550,7 +5651,7 @@
|
||||
)
|
||||
)
|
||||
)
|
||||
(func $std/array/createReverseOrderedElementsArray (; 86 ;) (type $ii) (param $0 i32) (result i32)
|
||||
(func $std/array/createReverseOrderedElementsArray (; 88 ;) (type $ii) (param $0 i32) (result i32)
|
||||
(local $1 i32)
|
||||
(set_local $1
|
||||
(call $~lib/array/Array<i32>#constructor
|
||||
@ -5598,7 +5699,7 @@
|
||||
)
|
||||
(get_local $1)
|
||||
)
|
||||
(func $start~anonymous|48 (; 87 ;) (type $iii) (param $0 i32) (param $1 i32) (result i32)
|
||||
(func $start~anonymous|48 (; 89 ;) (type $iii) (param $0 i32) (param $1 i32) (result i32)
|
||||
(i32.sub
|
||||
(i32.load
|
||||
(get_local $0)
|
||||
@ -5608,7 +5709,7 @@
|
||||
)
|
||||
)
|
||||
)
|
||||
(func $~lib/memory/compare_memory (; 88 ;) (type $iiii) (param $0 i32) (param $1 i32) (param $2 i32) (result i32)
|
||||
(func $~lib/memory/compare_memory (; 90 ;) (type $iiii) (param $0 i32) (param $1 i32) (param $2 i32) (result i32)
|
||||
(if
|
||||
(i32.eq
|
||||
(get_local $0)
|
||||
@ -5668,7 +5769,7 @@
|
||||
(i32.const 0)
|
||||
)
|
||||
)
|
||||
(func $~lib/string/String.__gt (; 89 ;) (type $iii) (param $0 i32) (param $1 i32) (result i32)
|
||||
(func $~lib/string/String.__gt (; 91 ;) (type $iii) (param $0 i32) (param $1 i32) (result i32)
|
||||
(local $2 i32)
|
||||
(local $3 i32)
|
||||
(if
|
||||
@ -5752,7 +5853,7 @@
|
||||
(i32.const 0)
|
||||
)
|
||||
)
|
||||
(func $~lib/string/String.__lt (; 90 ;) (type $iii) (param $0 i32) (param $1 i32) (result i32)
|
||||
(func $~lib/string/String.__lt (; 92 ;) (type $iii) (param $0 i32) (param $1 i32) (result i32)
|
||||
(local $2 i32)
|
||||
(local $3 i32)
|
||||
(if
|
||||
@ -5836,7 +5937,7 @@
|
||||
(i32.const 0)
|
||||
)
|
||||
)
|
||||
(func $start~anonymous|49 (; 91 ;) (type $iii) (param $0 i32) (param $1 i32) (result i32)
|
||||
(func $start~anonymous|49 (; 93 ;) (type $iii) (param $0 i32) (param $1 i32) (result i32)
|
||||
(i32.sub
|
||||
(call $~lib/string/String.__gt
|
||||
(get_local $0)
|
||||
@ -5848,7 +5949,7 @@
|
||||
)
|
||||
)
|
||||
)
|
||||
(func $~lib/string/String.__eq (; 92 ;) (type $iii) (param $0 i32) (param $1 i32) (result i32)
|
||||
(func $~lib/string/String.__eq (; 94 ;) (type $iii) (param $0 i32) (param $1 i32) (result i32)
|
||||
(local $2 i32)
|
||||
(if
|
||||
(i32.eq
|
||||
@ -5910,7 +6011,7 @@
|
||||
)
|
||||
)
|
||||
)
|
||||
(func $~lib/string/String.__ne (; 93 ;) (type $iii) (param $0 i32) (param $1 i32) (result i32)
|
||||
(func $~lib/string/String.__ne (; 95 ;) (type $iii) (param $0 i32) (param $1 i32) (result i32)
|
||||
(i32.eqz
|
||||
(call $~lib/string/String.__eq
|
||||
(get_local $0)
|
||||
@ -5918,7 +6019,7 @@
|
||||
)
|
||||
)
|
||||
)
|
||||
(func $std/array/isArraysEqual<String> (; 94 ;) (type $iiii) (param $0 i32) (param $1 i32) (param $2 i32) (result i32)
|
||||
(func $std/array/isArraysEqual<String> (; 96 ;) (type $iiii) (param $0 i32) (param $1 i32) (param $2 i32) (result i32)
|
||||
(local $3 i32)
|
||||
(if
|
||||
(i32.eqz
|
||||
@ -5979,7 +6080,7 @@
|
||||
)
|
||||
(i32.const 1)
|
||||
)
|
||||
(func $std/array/isArraysEqual<String>|trampoline (; 95 ;) (type $iiii) (param $0 i32) (param $1 i32) (param $2 i32) (result i32)
|
||||
(func $std/array/isArraysEqual<String>|trampoline (; 97 ;) (type $iiii) (param $0 i32) (param $1 i32) (param $2 i32) (result i32)
|
||||
(block $1of1
|
||||
(block $0of1
|
||||
(block $oob
|
||||
@ -6002,7 +6103,7 @@
|
||||
(get_local $2)
|
||||
)
|
||||
)
|
||||
(func $~lib/internal/string/allocate (; 96 ;) (type $ii) (param $0 i32) (result i32)
|
||||
(func $~lib/internal/string/allocate (; 98 ;) (type $ii) (param $0 i32) (result i32)
|
||||
(local $1 i32)
|
||||
(if
|
||||
(i32.eqz
|
||||
@ -6049,7 +6150,7 @@
|
||||
)
|
||||
(get_local $1)
|
||||
)
|
||||
(func $~lib/string/String#charAt (; 97 ;) (type $iii) (param $0 i32) (param $1 i32) (result i32)
|
||||
(func $~lib/string/String#charAt (; 99 ;) (type $iii) (param $0 i32) (param $1 i32) (result i32)
|
||||
(local $2 i32)
|
||||
(if
|
||||
(i32.eqz
|
||||
@ -6094,7 +6195,7 @@
|
||||
)
|
||||
(get_local $2)
|
||||
)
|
||||
(func $~lib/string/String#concat (; 98 ;) (type $iii) (param $0 i32) (param $1 i32) (result i32)
|
||||
(func $~lib/string/String#concat (; 100 ;) (type $iii) (param $0 i32) (param $1 i32) (result i32)
|
||||
(local $2 i32)
|
||||
(local $3 i32)
|
||||
(local $4 i32)
|
||||
@ -6181,7 +6282,7 @@
|
||||
)
|
||||
(get_local $2)
|
||||
)
|
||||
(func $~lib/string/String.__concat (; 99 ;) (type $iii) (param $0 i32) (param $1 i32) (result i32)
|
||||
(func $~lib/string/String.__concat (; 101 ;) (type $iii) (param $0 i32) (param $1 i32) (result i32)
|
||||
(if
|
||||
(i32.eqz
|
||||
(get_local $0)
|
||||
@ -6195,7 +6296,7 @@
|
||||
(get_local $1)
|
||||
)
|
||||
)
|
||||
(func $std/array/createRandomString (; 100 ;) (type $ii) (param $0 i32) (result i32)
|
||||
(func $std/array/createRandomString (; 102 ;) (type $ii) (param $0 i32) (result i32)
|
||||
(local $1 i32)
|
||||
(local $2 i32)
|
||||
(set_local $1
|
||||
@ -6240,7 +6341,7 @@
|
||||
)
|
||||
(get_local $1)
|
||||
)
|
||||
(func $std/array/createRandomStringArray (; 101 ;) (type $ii) (param $0 i32) (result i32)
|
||||
(func $std/array/createRandomStringArray (; 103 ;) (type $ii) (param $0 i32) (result i32)
|
||||
(local $1 i32)
|
||||
(set_local $1
|
||||
(call $~lib/array/Array<i32>#constructor
|
||||
@ -6284,7 +6385,7 @@
|
||||
)
|
||||
(get_local $1)
|
||||
)
|
||||
(func $start (; 102 ;) (type $v)
|
||||
(func $start (; 104 ;) (type $v)
|
||||
(set_global $~lib/allocator/arena/startOffset
|
||||
(i32.and
|
||||
(i32.add
|
||||
@ -9503,7 +9604,7 @@
|
||||
(i32.const 512)
|
||||
)
|
||||
)
|
||||
(call $std/array/assertSorted<i32>
|
||||
(call $std/array/assertSorted<Array<i32>>
|
||||
(get_global $std/array/reversedNested512)
|
||||
(i32.const 47)
|
||||
)
|
||||
@ -9512,11 +9613,11 @@
|
||||
(i32.const 512)
|
||||
)
|
||||
)
|
||||
(call $std/array/assertSorted<i32>
|
||||
(call $std/array/assertSorted<Array<i32>>
|
||||
(get_global $std/array/reversedElements512)
|
||||
(i32.const 48)
|
||||
)
|
||||
(call $std/array/assertSorted<i32>
|
||||
(call $std/array/assertSorted<Array<i32>>
|
||||
(get_global $std/array/randomStringsActual)
|
||||
(i32.const 49)
|
||||
)
|
||||
@ -9548,7 +9649,7 @@
|
||||
(i32.const 400)
|
||||
)
|
||||
)
|
||||
(call $std/array/assertSorted<i32>
|
||||
(call $std/array/assertSorted<Array<i32>>
|
||||
(get_global $std/array/randomStrings400)
|
||||
(i32.const 50)
|
||||
)
|
||||
|
@ -672,8 +672,8 @@ assertSorted<Proxy<i32>>(reversedElements512, (a: Proxy<i32>, b: Proxy<i32>): i3
|
||||
|
||||
// Test sorting strings
|
||||
|
||||
var randomStringsActual: string[] = ['a', 'b', 'a', 'ab', 'ba', '', null];
|
||||
var randomStringsExpected: string[] = ['', 'a', 'a', 'ab', 'b', 'ba', null];
|
||||
var randomStringsActual: string[] = ["a", "b", "a", "ab", "ba", "", null];
|
||||
var randomStringsExpected: string[] = ["", "a", "a", "ab", "b", "ba", null];
|
||||
assertSorted<string>(randomStringsActual, (a: string, b: string): i32 => <i32>(a > b) - <i32>(a < b));
|
||||
assert(isArraysEqual<string>(randomStringsActual, randomStringsExpected));
|
||||
|
||||
|
File diff suppressed because it is too large
Load Diff
Loading…
x
Reference in New Issue
Block a user