Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(array): impl public methods of Array for ArrayView #1275

Closed
wants to merge 11 commits into from
4 changes: 0 additions & 4 deletions array/array.mbt
Original file line number Diff line number Diff line change
Expand Up @@ -87,10 +87,6 @@ pub fn Array::shuffle_in_place[T](arr : Array[T], rand~ : (Int) -> Int) -> Unit
}
}

test {

}

///|
/// Shuffle the array using Knuth shuffle
///
Expand Down
22 changes: 22 additions & 0 deletions array/array.mbti
Original file line number Diff line number Diff line change
Expand Up @@ -63,8 +63,30 @@ impl Array {


impl ArrayView {
all[T](Self[T], (T) -> Bool) -> Bool
binary_search[T : Compare](Self[T], T) -> Result[Int, Int]
binary_search_by[T](Self[T], (T) -> Int) -> Result[Int, Int]
chunk_by[T](Self[T], (T, T) -> Bool) -> Self[Self[T]]
chunks[T](Self[T], Int) -> Self[Self[T]]
contains[T : Eq](Self[T], T) -> Bool
each[T](Self[T], (T) -> Unit) -> Unit
eachi[T](Self[T], (Int, T) -> Unit) -> Unit
filter[T](Self[T], (T) -> Bool) -> Self[T]
flatten[T](Self[Self[T]]) -> Self[T]
is_sorted[T : Compare](Self[T]) -> Bool
last[T](Self[T]) -> T?
map_inplace[T](Self[T], (T) -> T) -> Unit
map_option[A, B](Self[A], (A) -> B?) -> Self[B]
mapi_inplace[T](Self[T], (Int, T) -> T) -> Unit
rev_each[T](Self[T], (T) -> Unit) -> Unit
rev_eachi[T](Self[T], (Int, T) -> Unit) -> Unit
rev_inplace[T](Self[T]) -> Unit
search[T : Eq](Self[T], T) -> Int?
search_by[T](Self[T], (T) -> Bool) -> Int?
sort[T : Compare](Self[T]) -> Unit
sort_by[T](Self[T], (T, T) -> Int) -> Unit
sort_by_key[T, K : Compare](Self[T], (T) -> K) -> Unit
split[T](Self[T], (T) -> Bool) -> Self[Self[T]]
}

// Type aliases
Expand Down
7 changes: 0 additions & 7 deletions array/array_test.mbt
Original file line number Diff line number Diff line change
Expand Up @@ -353,13 +353,6 @@ test "repeat" {
assert_eq!(vv.length(), 4)
}

test "flatten" {
let v = [[3, 4], [5, 6]]
let vv = v.flatten()
assert_eq!(vv, [3, 4, 5, 6])
assert_eq!(vv.length(), 4)
}

test "fold" {
let sum = [1, 2, 3, 4, 5].fold(init=0, fn { sum, elem => sum + elem })
assert_eq!(sum, 15)
Expand Down
4 changes: 2 additions & 2 deletions array/fixedarray_sort.mbt
Original file line number Diff line number Diff line change
Expand Up @@ -523,9 +523,9 @@ test "stable_sort_complex" {
index += 1
}
}
assert_false!(is_sorted(arr))
assert_false!(arr.is_sorted())
arr.stable_sort()
assert_true!(is_sorted(arr))
assert_true!(arr.is_sorted())
}

test "find_streak with empty array" {
Expand Down
6 changes: 6 additions & 0 deletions array/sort.mbt
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,12 @@ pub fn sort[T : Compare](self : Array[T]) -> Unit {
quick_sort(self[:len], None, get_limit(len))
}

///|
pub fn sort[T : Compare](self : ArrayView[T]) -> Unit {
let len = self.length()
quick_sort(self[:len], None, get_limit(len))
}

///|
fn quick_sort[T : Compare](arr : ArrayView[T], pred : T?, limit : Int) -> Unit {
let mut limit = limit
Expand Down
15 changes: 15 additions & 0 deletions array/sort_by.mbt
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,16 @@ pub fn sort_by_key[T, K : Compare](self : Array[T], map : (T) -> K) -> Unit {
)
}

///|
pub fn sort_by_key[T, K : Compare](self : ArrayView[T], map : (T) -> K) -> Unit {
quick_sort_by(
self,
fn(a, b) { map(a).compare(map(b)) },
None,
get_limit(self.length()),
)
}

///|
/// Sorts the array with a custom comparison function.
///
Expand All @@ -49,6 +59,11 @@ pub fn sort_by[T](self : Array[T], cmp : (T, T) -> Int) -> Unit {
quick_sort_by(self[:], cmp, None, get_limit(self.length()))
}

///|
pub fn sort_by[T](self : ArrayView[T], cmp : (T, T) -> Int) -> Unit {
quick_sort_by(self[:], cmp, None, get_limit(self.length()))
}

///|
fn quick_sort_by[T](
arr : ArrayView[T],
Expand Down
268 changes: 268 additions & 0 deletions array/view.mbt
Original file line number Diff line number Diff line change
Expand Up @@ -27,3 +27,271 @@ pub fn each[T](self : ArrayView[T], f : (T) -> Unit) -> Unit {
f(self[i])
}
}

///|
pub fn rev_each[T](self : ArrayView[T], f : (T) -> Unit) -> Unit {
let len = self.length()
for i in 0..<len {
f(self[len - i - 1])
}
}

///|
pub fn eachi[T](self : ArrayView[T], f : (Int, T) -> Unit) -> Unit {
for i, v in self {
f(i, v)
}
}

///|
pub fn rev_eachi[T](self : ArrayView[T], f : (Int, T) -> Unit) -> Unit {
let len = self.length()
for i in 0..<len {
f(i, self[len - i - 1])
}
}

///|
/// Compares two arrayviews for equality of items, ignoring start/end positions.
pub impl[T : Eq] Eq for ArrayView[T] with op_equal(self, other) {
guard self.length() == other.length() else { return false }
for i in 0..<self.length() {
if self[i] != other[i] {
break false
}
} else {
true
}
}

///|
pub impl[T : Compare] Compare for ArrayView[T] with compare(self, other) -> Int {
let len_self = self.length()
let len_other = other.length()
if len_self < len_other {
-1
} else if len_self > len_other {
1
} else {
for i in 0..<len_self {
let cmp = self[i].compare(other[i])
if cmp != 0 {
break cmp
}
} else {
0
}
}
}

///|
pub fn filter[T](self : ArrayView[T], f : (T) -> Bool) -> ArrayView[T] {
let arr = []
for v in self {
if f(v) {
arr.push(v)
}
}
arr[:]
}

///|
pub fn all[T](self : ArrayView[T], f : (T) -> Bool) -> Bool {
for i in 0..<self.length() {
if f(self[i]).not() {
return false
}
}
true
}

///|
pub fn contains[T : Eq](self : ArrayView[T], value : T) -> Bool {
for v in self {
if v == value {
break true
}
} else {
false
}
}

///|
pub fn is_sorted[T : Compare](self : ArrayView[T]) -> Bool {
for i in 1..<self.length() {
if self[i - 1] > self[i] {
break false
}
} else {
true
}
}

///|
pub fn search[T : Eq](self : ArrayView[T], value : T) -> Int? {
for i = 0; i < self.length(); i = i + 1 {
if self[i] == value {
return Some(i)
}
}
None
}

///|
pub fn search_by[T](self : ArrayView[T], f : (T) -> Bool) -> Int? {
for i, v in self {
if f(v) {
break Some(i)
}
} else {
None
}
}

///|
pub fn last[T](self : ArrayView[T]) -> T? {
match self {
[] => None
[.., last] => Some(last)
}
}

///|
pub fn map_option[A, B](self : ArrayView[A], f : (A) -> B?) -> ArrayView[B] {
let result = []
self.each(
fn {
x =>
match f(x) {
None => ()
Some(x) => result.push(x)
}
},
)
result[:]
}

///|
pub fn chunks[T](self : ArrayView[T], size : Int) -> ArrayView[ArrayView[T]] {
let chunks = []
let mut i = 0
while i < self.length() {
let chunk = Array::new(capacity=size)
for j = 0; j < size && i < self.length(); j = j + 1 {
chunk.push(self[i])
i = i + 1
}
chunks.push(chunk[:])
}
chunks[:]
}

///|
pub fn chunk_by[T](
self : ArrayView[T],
pred : (T, T) -> Bool
) -> ArrayView[ArrayView[T]] {
let chunks = []
let mut i = 0
while i < self.length() {
let chunk = []
chunk.push(self[i])
i = i + 1
while i < self.length() && pred(self[i - 1], self[i]) {
chunk.push(self[i])
i = i + 1
}
chunks.push(chunk[:])
}
chunks[:]
}

///|
pub fn split[T](
self : ArrayView[T],
pred : (T) -> Bool
) -> ArrayView[ArrayView[T]] {
let chunks = []
let mut i = 0
while i < self.length() {
let chunk = []
while i < self.length() && pred(self[i]).not() {
chunk.push(self[i])
i = i + 1
}
chunks.push(chunk[:])
i = i + 1
}
chunks[:]
}

///|
pub fn map_inplace[T](self : ArrayView[T], f : (T) -> T) -> Unit {
for i, v in self {
self[i] = f(v)
}
}

///|
pub fn mapi_inplace[T](self : ArrayView[T], f : (Int, T) -> T) -> Unit {
for i, v in self {
self[i] = f(i, v)
}
}

///|
pub fn binary_search[T : Compare](
self : ArrayView[T],
value : T
) -> Result[Int, Int] {
let len = self.length()
for i = 0, j = len; i < j; {
let h = i + (j - i) / 2
// Note even if self[h] == value, we still continue the search
// because we want to find the leftmost match
if self.op_get(h) < value {
continue h + 1, j
} else {
continue i, h
}
} else {
if i < len && self.op_get(i) == value {
Ok(i)
} else {
Err(i)
}
}
}

///|
pub fn binary_search_by[T](
self : ArrayView[T],
cmp : (T) -> Int
) -> Result[Int, Int] {
let len = self.length()
for i = 0, j = len; i < j; {
let h = i + (j - i) / 2
// Note even if self[h] == value, we still continue the search
// because we want to find the leftmost match
if cmp(self.op_get(h)) < 0 {
continue h + 1, j
} else {
continue i, h
}
} else {
if i < len && cmp(self.op_get(i)) == 0 {
Ok(i)
} else {
Err(i)
}
}
}

///|
pub fn flatten[T](self : ArrayView[ArrayView[T]]) -> ArrayView[T] {
let v = []
for view in self {
v.push_iter(view.iter())
}
v[:]
}
Loading
Loading