Skip to content

Commit f28eddb

Browse files
fix: migrate sort implementation
1 parent 7326e9b commit f28eddb

File tree

7 files changed

+123
-59
lines changed

7 files changed

+123
-59
lines changed

array/fixedarray_sort.mbt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -98,7 +98,7 @@ fn[T : Compare] merge(arr : FixedArraySlice[T], mid : Int) -> Unit {
9898
for i in 0..<buf.length() {
9999
buf[i] = arr[mid + i]
100100
}
101-
let buf = { array: buf, start: 0, end: buf_len }
101+
let buf : FixedArraySlice[T] = { array: buf, start: 0, end: buf_len }
102102
let buf_remaining = for p1 = mid - 1, p2 = buf_len - 1, p = mid + buf_len - 1; p1 >=
103103
0 &&
104104
p2 >= 0; {

array/pkg.generated.mbti

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -84,15 +84,9 @@ fn[A] ArrayView::iter(Self[A]) -> Iter[A]
8484
fn[A] ArrayView::iter2(Self[A]) -> Iter2[Int, A]
8585
fn[A : @string.ToStringView] ArrayView::join(Self[A], StringView) -> String
8686
fn[T, U] ArrayView::map(Self[T], (T) -> U raise?) -> Array[U] raise?
87-
#deprecated
88-
fn[T] ArrayView::map_inplace(Self[T], (T) -> T raise?) -> Unit raise?
8987
fn[T, U] ArrayView::mapi(Self[T], (Int, T) -> U raise?) -> Array[U] raise?
90-
#deprecated
91-
fn[T] ArrayView::mapi_inplace(Self[T], (Int, T) -> T raise?) -> Unit raise?
9288
fn[A, B] ArrayView::rev_fold(Self[A], init~ : B, (B, A) -> B raise?) -> B raise?
9389
fn[A, B] ArrayView::rev_foldi(Self[A], init~ : B, (Int, B, A) -> B raise?) -> B raise?
94-
#deprecated
95-
fn[T] ArrayView::rev_inplace(Self[T]) -> Unit
9690
fn[T] ArrayView::to_array(Self[T]) -> Array[T]
9791
fn ArrayView::unsafe_extract_bit(Self[Byte], Int, Int) -> UInt
9892
fn ArrayView::unsafe_extract_byte(Self[Byte], Int, Int) -> UInt

array/slice.mbt

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -67,3 +67,58 @@ fn[T] FixedArraySlice::slice(
6767
) -> FixedArraySlice[T] {
6868
{ array: self.array, start: self.start + start, end: self.start + end }
6969
}
70+
71+
///|
72+
/// TODO: use specific type for non-js backend
73+
/// Notice: may need to move to builtin
74+
priv struct ArraySlice[T] {
75+
array : Array[T]
76+
start : Int
77+
end : Int
78+
}
79+
80+
///|
81+
fn[T] ArraySlice::length(self : ArraySlice[T]) -> Int {
82+
self.end - self.start
83+
}
84+
85+
///|
86+
#alias("_[_]")
87+
fn[T] ArraySlice::at(self : ArraySlice[T], index : Int) -> T {
88+
self.array[self.start + index]
89+
}
90+
91+
///|
92+
fn[T] ArraySlice::swap(self : ArraySlice[T], a : Int, b : Int) -> Unit {
93+
let i = a + self.start
94+
let j = b + self.start
95+
if i >= self.end || j >= self.end || i < self.start || j < self.start {
96+
let len = self.length()
97+
abort(
98+
"index out of bounds: the len is from 0 to \{len} but the index is (\{a}, \{b})",
99+
)
100+
}
101+
let temp = self.array.unsafe_get(i)
102+
self.array.unsafe_set(i, self.array.unsafe_get(j))
103+
self.array.unsafe_set(j, temp)
104+
}
105+
106+
///|
107+
fn[T] ArraySlice::rev_inplace(self : ArraySlice[T]) -> Unit {
108+
let len = self.length()
109+
let mid_len = len / 2
110+
for i in 0..<mid_len {
111+
let j = len - i - 1
112+
self.swap(i, j)
113+
}
114+
}
115+
116+
///|
117+
#alias("_[_:_]")
118+
fn[T] ArraySlice::sub(
119+
self : ArraySlice[T],
120+
start? : Int = 0,
121+
end? : Int = self.length(),
122+
) -> ArraySlice[T] {
123+
{ array: self.array, start: self.start + start, end: self.start + end }
124+
}

array/sort.mbt

Lines changed: 37 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -26,11 +26,11 @@
2626
/// ```
2727
pub fn[T : Compare] sort(self : Array[T]) -> Unit {
2828
let len = self.length()
29-
quick_sort(self[:len], None, get_limit(len))
29+
quick_sort({ array: self, start: 0, end: len }, None, get_limit(len))
3030
}
3131
3232
///|
33-
fn[T : Compare] quick_sort(arr : ArrayView[T], pred : T?, limit : Int) -> Unit {
33+
fn[T : Compare] quick_sort(arr : ArraySlice[T], pred : T?, limit : Int) -> Unit {
3434
let mut limit = limit
3535
let mut arr = arr
3636
let mut pred = pred
@@ -41,7 +41,7 @@ fn[T : Compare] quick_sort(arr : ArrayView[T], pred : T?, limit : Int) -> Unit {
4141
let len = arr.length()
4242
if len <= insertion_sort_len {
4343
if len >= 2 {
44-
ArrayView::insertion_sort(arr)
44+
insertion_sort(arr)
4545
}
4646
return
4747
}
@@ -60,7 +60,10 @@ fn[T : Compare] quick_sort(arr : ArrayView[T], pred : T?, limit : Int) -> Unit {
6060
}
6161
let (pivot, partitioned) = partition(arr, pivot_index)
6262
was_partitioned = partitioned
63-
balanced = minimum(pivot, len - pivot) >= len / 8
63+
balanced = {
64+
let diff = len - pivot
65+
(if pivot < diff { pivot } else { diff }) >= len / 8
66+
}
6467
if !balanced {
6568
limit -= 1
6669
}
@@ -107,7 +110,7 @@ fn get_limit(len : Int) -> Int {
107110
/// It will only tolerate at most 8 unsorted elements. The time complexity is O(n).
108111
///
109112
/// Returns whether the array is sorted.
110-
fn[T : Compare] try_bubble_sort(arr : ArrayView[T]) -> Bool {
113+
fn[T : Compare] try_bubble_sort(arr : ArraySlice[T]) -> Bool {
111114
let max_tries = 8
112115
let mut tries = 0
113116
for i in 1..<arr.length() {
@@ -128,7 +131,7 @@ fn[T : Compare] try_bubble_sort(arr : ArrayView[T]) -> Bool {
128131
129132
///|
130133
/// Used when the array is small enough (<=16) to avoid recursion overhead.
131-
fn[T : Compare] ArrayView::insertion_sort(arr : ArrayView[T]) -> Unit {
134+
fn[T : Compare] insertion_sort(arr : ArraySlice[T]) -> Unit {
132135
for i in 1..<arr.length() {
133136
for j = i; j > 0 && arr[j - 1] > arr[j]; j = j - 1 {
134137
arr.swap(j, j - 1)
@@ -137,7 +140,10 @@ fn[T : Compare] ArrayView::insertion_sort(arr : ArrayView[T]) -> Unit {
137140
}
138141
139142
///|
140-
fn[T : Compare] partition(arr : ArrayView[T], pivot_index : Int) -> (Int, Bool) {
143+
fn[T : Compare] partition(
144+
arr : ArraySlice[T],
145+
pivot_index : Int,
146+
) -> (Int, Bool) {
141147
arr.swap(pivot_index, arr.length() - 1)
142148
let pivot = arr[arr.length() - 1]
143149
let mut i = 0
@@ -161,7 +167,7 @@ fn[T : Compare] partition(arr : ArrayView[T], pivot_index : Int) -> (Int, Bool)
161167
/// It avoids worst case performance by choosing a pivot that is likely to be close to the median.
162168
///
163169
/// Returns the pivot index and whether the array is likely sorted.
164-
fn[T : Compare] choose_pivot(arr : ArrayView[T]) -> (Int, Bool) {
170+
fn[T : Compare] choose_pivot(arr : ArraySlice[T]) -> (Int, Bool) {
165171
let len = arr.length()
166172
let use_median_of_medians = 50
167173
let max_swaps = 4 * 3
@@ -195,7 +201,7 @@ fn[T : Compare] choose_pivot(arr : ArrayView[T]) -> (Int, Bool) {
195201
}
196202
197203
///|
198-
fn[T : Compare] heap_sort(arr : ArrayView[T]) -> Unit {
204+
fn[T : Compare] heap_sort(arr : ArraySlice[T]) -> Unit {
199205
let len = arr.length()
200206
for i = len / 2 - 1; i >= 0; i = i - 1 {
201207
sift_down(arr, i)
@@ -207,7 +213,7 @@ fn[T : Compare] heap_sort(arr : ArrayView[T]) -> Unit {
207213
}
208214
209215
///|
210-
fn[T : Compare] sift_down(arr : ArrayView[T], index : Int) -> Unit {
216+
fn[T : Compare] sift_down(arr : ArraySlice[T], index : Int) -> Unit {
211217
let mut index = index
212218
let len = arr.length()
213219
let mut child = index * 2 + 1
@@ -253,19 +259,19 @@ fn test_sort(f : (Array[Int]) -> Unit) -> Unit raise {
253259
///|
254260
test "try_bubble_sort" {
255261
let arr = [8, 7, 6, 5, 4, 3, 2, 1]
256-
let sorted = try_bubble_sort(arr[0:8])
262+
let sorted = try_bubble_sort({ array: arr, start: 0, end: 8 })
257263
inspect(sorted, content="true")
258264
assert_eq(arr, [1, 2, 3, 4, 5, 6, 7, 8])
259265
}
260266
261267
///|
262268
test "heap_sort" {
263-
test_sort(arr => heap_sort(arr[:]))
269+
test_sort(arr => heap_sort({ array: arr, start: 0, end: arr.length() }))
264270
}
265271
266272
///|
267273
test "insertion_sort" {
268-
test_sort(arr => ArrayView::insertion_sort(arr[:]))
274+
test_sort(arr => insertion_sort({ array: arr, start: 0, end: arr.length() }))
269275
}
270276
271277
///|
@@ -287,29 +293,29 @@ test "sort with same pivot optimization" {
287293
///|
288294
test "heap_sort coverage" {
289295
let arr = [5, 4, 3, 2, 1]
290-
heap_sort(arr[:])
296+
heap_sort({ array: arr, start: 0, end: arr.length() })
291297
assert_eq(arr, [1, 2, 3, 4, 5])
292298
let arr2 = [1, 2, 3, 4, 5]
293-
heap_sort(arr2[:])
299+
heap_sort({ array: arr2, start: 0, end: arr2.length() })
294300
assert_eq(arr2, [1, 2, 3, 4, 5])
295301
let arr2 = [1, 2, 3, 4, 5]
296-
heap_sort(arr2[:])
302+
heap_sort({ array: arr2, start: 0, end: arr2.length() })
297303
assert_eq(arr2, [1, 2, 3, 4, 5])
298304
let arr3 = [5, 5, 5, 5, 1]
299-
heap_sort(arr3[:])
305+
heap_sort({ array: arr3, start: 0, end: arr3.length() })
300306
assert_eq(arr3, [1, 5, 5, 5, 5])
301307
}
302308
303309
///|
304310
test "quick_sort limit check" {
305311
let arr = [5, 4, 3, 2, 1]
306-
quick_sort(arr[:], None, 0)
312+
quick_sort({ array: arr, start: 0, end: arr.length() }, None, 0)
307313
assert_eq(arr, [1, 2, 3, 4, 5])
308314
let arr2 = [1, 2, 3, 4, 5]
309-
quick_sort(arr2[:], None, 0)
315+
quick_sort({ array: arr2, start: 0, end: arr2.length() }, None, 0)
310316
assert_eq(arr2, [1, 2, 3, 4, 5])
311317
let arr3 = [5, 5, 5, 5, 1]
312-
quick_sort(arr3[:], None, 0)
318+
quick_sort({ array: arr3, start: 0, end: arr3.length() }, None, 0)
313319
assert_eq(arr3, [1, 5, 5, 5, 5])
314320
}
315321
@@ -319,16 +325,16 @@ test "quick_sort with pred check" {
319325
for i = 16; i >= 0; i = i - 1 {
320326
arr.push(i)
321327
}
322-
quick_sort(arr[:], Some(8), 0)
328+
quick_sort({ array: arr, start: 0, end: arr.length() }, Some(8), 0)
323329
assert_eq(arr, [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16])
324330
let arr = [5, 4, 3, 2, 1]
325-
quick_sort(arr[:], Some(3), 0)
331+
quick_sort({ array: arr, start: 0, end: arr.length() }, Some(3), 0)
326332
assert_eq(arr, [1, 2, 3, 4, 5])
327333
let arr2 = [1, 2, 3, 4, 5]
328-
quick_sort(arr2[:], Some(3), 0)
334+
quick_sort({ array: arr2, start: 0, end: arr2.length() }, Some(3), 0)
329335
assert_eq(arr2, [1, 2, 3, 4, 5])
330336
let arr3 = [5, 5, 5, 5, 1]
331-
quick_sort(arr3[:], Some(3), 0)
337+
quick_sort({ array: arr3, start: 0, end: arr3.length() }, Some(3), 0)
332338
assert_eq(arr3, [1, 5, 5, 5, 5])
333339
}
334340
@@ -338,36 +344,36 @@ test "quick_sort with unbalanced partitions" {
338344
for i = 16; i >= 0; i = i - 1 {
339345
arr.push(if i >= 8 { i } else { 8 })
340346
}
341-
quick_sort(arr[:], Some(8), 42)
347+
quick_sort({ array: arr, start: 0, end: arr.length() }, Some(8), 42)
342348
assert_eq(arr, [8, 8, 8, 8, 8, 8, 8, 8, 8, 9, 10, 11, 12, 13, 14, 15, 16])
343349
let arr = [5, 4, 3, 2, 1]
344-
quick_sort(arr[:], None, 1)
350+
quick_sort({ array: arr, start: 0, end: arr.length() }, None, 1)
345351
assert_eq(arr, [1, 2, 3, 4, 5])
346352
let arr2 = [1, 2, 3, 4, 5]
347-
quick_sort(arr2[:], None, 1)
353+
quick_sort({ array: arr2, start: 0, end: arr2.length() }, None, 1)
348354
assert_eq(arr2, [1, 2, 3, 4, 5])
349355
let arr3 = [5, 5, 5, 5, 1]
350-
quick_sort(arr3[:], None, 1)
356+
quick_sort({ array: arr3, start: 0, end: arr3.length() }, None, 1)
351357
assert_eq(arr3, [1, 5, 5, 5, 5])
352358
}
353359
354360
///|
355361
test "quick_sort with pivot equal to pred" {
356362
let arr = [5, 4, 3, 2, 1]
357-
quick_sort(arr[:], Some(3), 0)
363+
quick_sort({ array: arr, start: 0, end: arr.length() }, Some(3), 0)
358364
assert_eq(arr, [1, 2, 3, 4, 5])
359365
}
360366
361367
///|
362368
test "quick_sort with pred less than all elements" {
363369
let arr = [5, 4, 3, 2, 1]
364-
quick_sort(arr[:], Some(0), 0)
370+
quick_sort({ array: arr, start: 0, end: arr.length() }, Some(0), 0)
365371
assert_eq(arr, [1, 2, 3, 4, 5])
366372
}
367373
368374
///|
369375
test "quick_sort with pred greater than all elements" {
370376
let arr = [5, 4, 3, 2, 1]
371-
quick_sort(arr[:], Some(6), 0)
377+
quick_sort({ array: arr, start: 0, end: arr.length() }, Some(6), 0)
372378
assert_eq(arr, [1, 2, 3, 4, 5])
373379
}

0 commit comments

Comments
 (0)