Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
44 changes: 0 additions & 44 deletions array/deprecated.mbt

This file was deleted.

2 changes: 1 addition & 1 deletion array/fixedarray_sort.mbt
Original file line number Diff line number Diff line change
Expand Up @@ -98,7 +98,7 @@ fn[T : Compare] merge(arr : FixedArraySlice[T], mid : Int) -> Unit {
for i in 0..<buf.length() {
buf[i] = arr[mid + i]
}
let buf = { array: buf, start: 0, end: buf_len }
let buf : FixedArraySlice[T] = { array: buf, start: 0, end: buf_len }
let buf_remaining = for p1 = mid - 1, p2 = buf_len - 1, p = mid + buf_len - 1; p1 >=
0 &&
p2 >= 0; {
Expand Down
6 changes: 0 additions & 6 deletions array/pkg.generated.mbti
Original file line number Diff line number Diff line change
Expand Up @@ -84,15 +84,9 @@ fn[A] ArrayView::iter(Self[A]) -> Iter[A]
fn[A] ArrayView::iter2(Self[A]) -> Iter2[Int, A]
fn[A : @string.ToStringView] ArrayView::join(Self[A], StringView) -> String
fn[T, U] ArrayView::map(Self[T], (T) -> U raise?) -> Array[U] raise?
#deprecated
fn[T] ArrayView::map_inplace(Self[T], (T) -> T raise?) -> Unit raise?
fn[T, U] ArrayView::mapi(Self[T], (Int, T) -> U raise?) -> Array[U] raise?
#deprecated
fn[T] ArrayView::mapi_inplace(Self[T], (Int, T) -> T raise?) -> Unit raise?
fn[A, B] ArrayView::rev_fold(Self[A], init~ : B, (B, A) -> B raise?) -> B raise?
fn[A, B] ArrayView::rev_foldi(Self[A], init~ : B, (Int, B, A) -> B raise?) -> B raise?
#deprecated
fn[T] ArrayView::rev_inplace(Self[T]) -> Unit
fn[T] ArrayView::to_array(Self[T]) -> Array[T]
fn ArrayView::unsafe_extract_bit(Self[Byte], Int, Int) -> UInt
fn ArrayView::unsafe_extract_byte(Self[Byte], Int, Int) -> UInt
Expand Down
55 changes: 55 additions & 0 deletions array/slice.mbt
Original file line number Diff line number Diff line change
Expand Up @@ -67,3 +67,58 @@ fn[T] FixedArraySlice::slice(
) -> FixedArraySlice[T] {
{ array: self.array, start: self.start + start, end: self.start + end }
}

///|
/// TODO: use specific type for non-js backend
/// Notice: may need to move to builtin
priv struct ArraySlice[T] {
array : Array[T]
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

cc @Yu-zh this is a valid use case where we would like it to be value type

start : Int
end : Int
}

///|
fn[T] ArraySlice::length(self : ArraySlice[T]) -> Int {
self.end - self.start
}

///|
#alias("_[_]")
fn[T] ArraySlice::at(self : ArraySlice[T], index : Int) -> T {
self.array[self.start + index]
}

///|
fn[T] ArraySlice::swap(self : ArraySlice[T], a : Int, b : Int) -> Unit {
let i = a + self.start
let j = b + self.start
if i >= self.end || j >= self.end || i < self.start || j < self.start {
let len = self.length()
abort(
"index out of bounds: the len is from 0 to \{len} but the index is (\{a}, \{b})",
)
}
let temp = self.array.unsafe_get(i)
self.array.unsafe_set(i, self.array.unsafe_get(j))
self.array.unsafe_set(j, temp)
}

///|
fn[T] ArraySlice::rev_inplace(self : ArraySlice[T]) -> Unit {
let len = self.length()
let mid_len = len / 2
for i in 0..<mid_len {
let j = len - i - 1
self.swap(i, j)
}
}

///|
#alias("_[_:_]")
fn[T] ArraySlice::sub(
self : ArraySlice[T],
start? : Int = 0,
end? : Int = self.length(),
) -> ArraySlice[T] {
{ array: self.array, start: self.start + start, end: self.start + end }
}
68 changes: 37 additions & 31 deletions array/sort.mbt
Original file line number Diff line number Diff line change
Expand Up @@ -26,11 +26,11 @@
/// ```
pub fn[T : Compare] sort(self : Array[T]) -> Unit {
let len = self.length()
quick_sort(self[:len], None, get_limit(len))
quick_sort({ array: self, start: 0, end: len }, None, get_limit(len))
}

///|
fn[T : Compare] quick_sort(arr : ArrayView[T], pred : T?, limit : Int) -> Unit {
fn[T : Compare] quick_sort(arr : ArraySlice[T], pred : T?, limit : Int) -> Unit {
let mut limit = limit
let mut arr = arr
let mut pred = pred
Expand All @@ -41,7 +41,7 @@ fn[T : Compare] quick_sort(arr : ArrayView[T], pred : T?, limit : Int) -> Unit {
let len = arr.length()
if len <= insertion_sort_len {
if len >= 2 {
ArrayView::insertion_sort(arr)
insertion_sort(arr)
}
return
}
Expand All @@ -60,7 +60,10 @@ fn[T : Compare] quick_sort(arr : ArrayView[T], pred : T?, limit : Int) -> Unit {
}
let (pivot, partitioned) = partition(arr, pivot_index)
was_partitioned = partitioned
balanced = minimum(pivot, len - pivot) >= len / 8
balanced = {
let diff = len - pivot
(if pivot < diff { pivot } else { diff }) >= len / 8
}
if !balanced {
limit -= 1
}
Expand Down Expand Up @@ -107,7 +110,7 @@ fn get_limit(len : Int) -> Int {
/// It will only tolerate at most 8 unsorted elements. The time complexity is O(n).
///
/// Returns whether the array is sorted.
fn[T : Compare] try_bubble_sort(arr : ArrayView[T]) -> Bool {
fn[T : Compare] try_bubble_sort(arr : ArraySlice[T]) -> Bool {
let max_tries = 8
let mut tries = 0
for i in 1..<arr.length() {
Expand All @@ -128,7 +131,7 @@ fn[T : Compare] try_bubble_sort(arr : ArrayView[T]) -> Bool {

///|
/// Used when the array is small enough (<=16) to avoid recursion overhead.
fn[T : Compare] ArrayView::insertion_sort(arr : ArrayView[T]) -> Unit {
fn[T : Compare] insertion_sort(arr : ArraySlice[T]) -> Unit {
for i in 1..<arr.length() {
for j = i; j > 0 && arr[j - 1] > arr[j]; j = j - 1 {
arr.swap(j, j - 1)
Expand All @@ -137,7 +140,10 @@ fn[T : Compare] ArrayView::insertion_sort(arr : ArrayView[T]) -> Unit {
}

///|
fn[T : Compare] partition(arr : ArrayView[T], pivot_index : Int) -> (Int, Bool) {
fn[T : Compare] partition(
arr : ArraySlice[T],
pivot_index : Int,
) -> (Int, Bool) {
arr.swap(pivot_index, arr.length() - 1)
let pivot = arr[arr.length() - 1]
let mut i = 0
Expand All @@ -161,7 +167,7 @@ fn[T : Compare] partition(arr : ArrayView[T], pivot_index : Int) -> (Int, Bool)
/// It avoids worst case performance by choosing a pivot that is likely to be close to the median.
///
/// Returns the pivot index and whether the array is likely sorted.
fn[T : Compare] choose_pivot(arr : ArrayView[T]) -> (Int, Bool) {
fn[T : Compare] choose_pivot(arr : ArraySlice[T]) -> (Int, Bool) {
let len = arr.length()
let use_median_of_medians = 50
let max_swaps = 4 * 3
Expand Down Expand Up @@ -195,7 +201,7 @@ fn[T : Compare] choose_pivot(arr : ArrayView[T]) -> (Int, Bool) {
}

///|
fn[T : Compare] heap_sort(arr : ArrayView[T]) -> Unit {
fn[T : Compare] heap_sort(arr : ArraySlice[T]) -> Unit {
let len = arr.length()
for i = len / 2 - 1; i >= 0; i = i - 1 {
sift_down(arr, i)
Expand All @@ -207,7 +213,7 @@ fn[T : Compare] heap_sort(arr : ArrayView[T]) -> Unit {
}

///|
fn[T : Compare] sift_down(arr : ArrayView[T], index : Int) -> Unit {
fn[T : Compare] sift_down(arr : ArraySlice[T], index : Int) -> Unit {
let mut index = index
let len = arr.length()
let mut child = index * 2 + 1
Expand Down Expand Up @@ -253,19 +259,19 @@ fn test_sort(f : (Array[Int]) -> Unit) -> Unit raise {
///|
test "try_bubble_sort" {
let arr = [8, 7, 6, 5, 4, 3, 2, 1]
let sorted = try_bubble_sort(arr[0:8])
let sorted = try_bubble_sort({ array: arr, start: 0, end: 8 })
inspect(sorted, content="true")
assert_eq(arr, [1, 2, 3, 4, 5, 6, 7, 8])
}

///|
test "heap_sort" {
test_sort(arr => heap_sort(arr[:]))
test_sort(arr => heap_sort({ array: arr, start: 0, end: arr.length() }))
}

///|
test "insertion_sort" {
test_sort(arr => ArrayView::insertion_sort(arr[:]))
test_sort(arr => insertion_sort({ array: arr, start: 0, end: arr.length() }))
}

///|
Expand All @@ -287,29 +293,29 @@ test "sort with same pivot optimization" {
///|
test "heap_sort coverage" {
let arr = [5, 4, 3, 2, 1]
heap_sort(arr[:])
heap_sort({ array: arr, start: 0, end: arr.length() })
assert_eq(arr, [1, 2, 3, 4, 5])
let arr2 = [1, 2, 3, 4, 5]
heap_sort(arr2[:])
heap_sort({ array: arr2, start: 0, end: arr2.length() })
assert_eq(arr2, [1, 2, 3, 4, 5])
let arr2 = [1, 2, 3, 4, 5]
heap_sort(arr2[:])
heap_sort({ array: arr2, start: 0, end: arr2.length() })
assert_eq(arr2, [1, 2, 3, 4, 5])
let arr3 = [5, 5, 5, 5, 1]
heap_sort(arr3[:])
heap_sort({ array: arr3, start: 0, end: arr3.length() })
assert_eq(arr3, [1, 5, 5, 5, 5])
}

///|
test "quick_sort limit check" {
let arr = [5, 4, 3, 2, 1]
quick_sort(arr[:], None, 0)
quick_sort({ array: arr, start: 0, end: arr.length() }, None, 0)
assert_eq(arr, [1, 2, 3, 4, 5])
let arr2 = [1, 2, 3, 4, 5]
quick_sort(arr2[:], None, 0)
quick_sort({ array: arr2, start: 0, end: arr2.length() }, None, 0)
assert_eq(arr2, [1, 2, 3, 4, 5])
let arr3 = [5, 5, 5, 5, 1]
quick_sort(arr3[:], None, 0)
quick_sort({ array: arr3, start: 0, end: arr3.length() }, None, 0)
assert_eq(arr3, [1, 5, 5, 5, 5])
}

Expand All @@ -319,16 +325,16 @@ test "quick_sort with pred check" {
for i = 16; i >= 0; i = i - 1 {
arr.push(i)
}
quick_sort(arr[:], Some(8), 0)
quick_sort({ array: arr, start: 0, end: arr.length() }, Some(8), 0)
assert_eq(arr, [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16])
let arr = [5, 4, 3, 2, 1]
quick_sort(arr[:], Some(3), 0)
quick_sort({ array: arr, start: 0, end: arr.length() }, Some(3), 0)
assert_eq(arr, [1, 2, 3, 4, 5])
let arr2 = [1, 2, 3, 4, 5]
quick_sort(arr2[:], Some(3), 0)
quick_sort({ array: arr2, start: 0, end: arr2.length() }, Some(3), 0)
assert_eq(arr2, [1, 2, 3, 4, 5])
let arr3 = [5, 5, 5, 5, 1]
quick_sort(arr3[:], Some(3), 0)
quick_sort({ array: arr3, start: 0, end: arr3.length() }, Some(3), 0)
assert_eq(arr3, [1, 5, 5, 5, 5])
}

Expand All @@ -338,36 +344,36 @@ test "quick_sort with unbalanced partitions" {
for i = 16; i >= 0; i = i - 1 {
arr.push(if i >= 8 { i } else { 8 })
}
quick_sort(arr[:], Some(8), 42)
quick_sort({ array: arr, start: 0, end: arr.length() }, Some(8), 42)
assert_eq(arr, [8, 8, 8, 8, 8, 8, 8, 8, 8, 9, 10, 11, 12, 13, 14, 15, 16])
let arr = [5, 4, 3, 2, 1]
quick_sort(arr[:], None, 1)
quick_sort({ array: arr, start: 0, end: arr.length() }, None, 1)
assert_eq(arr, [1, 2, 3, 4, 5])
let arr2 = [1, 2, 3, 4, 5]
quick_sort(arr2[:], None, 1)
quick_sort({ array: arr2, start: 0, end: arr2.length() }, None, 1)
assert_eq(arr2, [1, 2, 3, 4, 5])
let arr3 = [5, 5, 5, 5, 1]
quick_sort(arr3[:], None, 1)
quick_sort({ array: arr3, start: 0, end: arr3.length() }, None, 1)
assert_eq(arr3, [1, 5, 5, 5, 5])
}

///|
test "quick_sort with pivot equal to pred" {
let arr = [5, 4, 3, 2, 1]
quick_sort(arr[:], Some(3), 0)
quick_sort({ array: arr, start: 0, end: arr.length() }, Some(3), 0)
assert_eq(arr, [1, 2, 3, 4, 5])
}

///|
test "quick_sort with pred less than all elements" {
let arr = [5, 4, 3, 2, 1]
quick_sort(arr[:], Some(0), 0)
quick_sort({ array: arr, start: 0, end: arr.length() }, Some(0), 0)
assert_eq(arr, [1, 2, 3, 4, 5])
}

///|
test "quick_sort with pred greater than all elements" {
let arr = [5, 4, 3, 2, 1]
quick_sort(arr[:], Some(6), 0)
quick_sort({ array: arr, start: 0, end: arr.length() }, Some(6), 0)
assert_eq(arr, [1, 2, 3, 4, 5])
}
Loading
Loading