Skip to content

Commit

Permalink
Merge branch 'main' into trig-func-special-input
Browse files Browse the repository at this point in the history
  • Loading branch information
bobzhang authored Dec 24, 2024
2 parents 6e86abe + 86d7a26 commit a854b26
Show file tree
Hide file tree
Showing 4 changed files with 155 additions and 3 deletions.
63 changes: 60 additions & 3 deletions deque/deque.mbt
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,22 @@ pub fn T::from_array[A](arr : Array[A]) -> T[A] {
deq
}

///|
/// Creates a new copy of this deque.
pub fn T::copy[A](self : T[A]) -> T[A] {
let len = self.len
let deq = T::{
buf: UninitializedArray::make(len),
len,
head: 0,
tail: len - 1,
}
for i, x in self {
deq.buf[i] = x
}
deq
}

///|
pub fn T::of[A](arr : FixedArray[A]) -> T[A] {
let deq = T::{
Expand Down Expand Up @@ -542,12 +558,53 @@ pub fn shrink_to_fit[A](self : T[A]) -> Unit {
///|
pub fn iter[A](self : T[A]) -> Iter[A] {
Iter::new(fn(yield_) {
for i in 0..<self.length() {
guard let IterContinue = yield_(self[i]) else { x => break x }
guard not(self.is_empty()) else { IterContinue }
let { head, buf, len, .. } = self
let cap = buf.length()
let head_len = cap - head
if head_len >= len {
for i in head..<(head + len) {
guard let IterContinue = yield_(buf[i]) else { x => return x }

}
} else {
IterContinue
for i in head..<cap {
guard let IterContinue = yield_(buf[i]) else { x => return x }

}
for i in 0..<(len - head_len) {
guard let IterContinue = yield_(buf[i]) else { x => return x }

}
}
IterContinue
})
}

///|
pub fn iter2[A](self : T[A]) -> Iter2[Int, A] {
Iter2::new(fn(yield_) {
guard not(self.is_empty()) else { IterContinue }
let { head, buf, len, .. } = self
let cap = buf.length()
let head_len = cap - head
let mut j = 0
if head_len >= len {
for i in head..<(head + len) {
guard let IterContinue = yield_(j, buf[i]) else { x => return x }
j += 1
}
} else {
for i in head..<cap {
guard let IterContinue = yield_(j, buf[i]) else { x => return x }
j += 1
}
for i in 0..<(len - head_len) {
guard let IterContinue = yield_(j, buf[i]) else { x => return x }
j += 1
}
}
IterContinue
})
}

Expand Down
2 changes: 2 additions & 0 deletions deque/deque.mbti
Original file line number Diff line number Diff line change
Expand Up @@ -9,13 +9,15 @@ impl T {
capacity[A](Self[A]) -> Int
clear[A](Self[A]) -> Unit
contains[A : Eq](Self[A], A) -> Bool
copy[A](Self[A]) -> Self[A]
each[A](Self[A], (A) -> Unit) -> Unit
eachi[A](Self[A], (Int, A) -> Unit) -> Unit
from_array[A](Array[A]) -> Self[A]
from_iter[A](Iter[A]) -> Self[A]
front[A](Self[A]) -> A?
is_empty[A](Self[A]) -> Bool
iter[A](Self[A]) -> Iter[A]
iter2[A](Self[A]) -> Iter2[Int, A]
length[A](Self[A]) -> Int
map[A, U](Self[A], (A) -> U) -> Self[U]
mapi[A, U](Self[A], (Int, A) -> U) -> Self[U]
Expand Down
81 changes: 81 additions & 0 deletions deque/deque_test.mbt
Original file line number Diff line number Diff line change
Expand Up @@ -203,6 +203,15 @@ test "from_array" {
inspect!(@deque.of([1, 2, 3]), content="@deque.of([1, 2, 3])")
}

test "copy" {
inspect!((@deque.new() : @deque.T[Int]).copy(), content="@deque.of([])")
let deq = @deque.of([1, 2, 3])
let deq1 = deq.copy()
deq1[0] = 111
inspect!(deq, content="@deque.of([1, 2, 3])")
inspect!(deq1, content="@deque.of([111, 2, 3])")
}

test "op_set" {
let dv = @deque.of([1, 2, 3, 4, 5])
dv[1] = 3
Expand Down Expand Up @@ -365,3 +374,75 @@ test "from_iter empty iter" {
let dq : @deque.T[Int] = @deque.T::from_iter(Iter::empty())
inspect!(dq, content="@deque.of([])")
}

test "from_array with single element" {
let arr = [42]
let deque = @deque.T::from_array(arr)
assert_eq!(deque.length(), 1)
assert_eq!(deque.front(), Some(42))
assert_eq!(deque.back(), Some(42))
}

test "unsafe_pop_front after many push_front" {
let dq = @deque.new()
// First fill some elements to create a buffer with some capacity
for i = 0; i < 10; i = i + 1 {
dq.push_front(i)
}
// Pop all elements except one
for i = 0; i < 9; i = i + 1 {
dq.unsafe_pop_front()
}
// Now head should be at the end of buffer
// When we pop again, head should wrap around to 0
inspect!(dq.front(), content="Some(0)")
dq.unsafe_pop_front()
inspect!(dq.is_empty(), content="true")
}

test "unsafe_pop_back when tail needs to wrap around" {
let dq = @deque.new(capacity=2)
dq.push_back(1) // tail = 0
dq.push_back(2) // tail = 1
dq.unsafe_pop_front() // head = 1
dq.push_back(3) // tail = 0 (wraps around)
dq.unsafe_pop_back()
inspect!(dq.back(), content="Some(2)")
}

test "deque op_set wrapping case" {
let dq = @deque.new(capacity=4)
// Add elements until the deque wraps around
dq.push_back(1) // head=0, tail=0
dq.push_back(2) // head=0, tail=1
dq.push_back(3) // head=0, tail=2
dq.push_back(4) // head=0, tail=3
dq.push_front(0) // head=3, tail=3

// Now the deque is [0,1,2,3,4] with head=3, tail=3
// Setting dq[2] should trigger the uncovered branch
dq[2] = 10

// Verify the change
inspect!(dq, content="@deque.of([0, 10, 2, 3, 4])")
}

test "iter when tail needs to wrap around" {
let dq = @deque.new(capacity=2)
dq.push_back(1) // tail = 0
dq.push_back(2) // tail = 1
dq.unsafe_pop_front() // head = 1
dq.push_back(3) // tail = 0 (wraps around)
inspect!(dq.iter().to_array(), content="[2, 3]")
inspect!(dq.iter().filter(fn(x) { x % 2 == 0 }).to_array(), content="[2]")
inspect!(dq.iter().filter(fn(x) { x % 2 != 0 }).to_array(), content="[3]")
}

test "iter2 when tail needs to wrap around" {
let dq = @deque.new(capacity=2)
dq.push_back(1) // tail = 0
dq.push_back(2) // tail = 1
dq.unsafe_pop_front() // head = 1
dq.push_back(3) // tail = 0 (wraps around)
inspect!(dq.iter2().to_array(), content="[(0, 2), (1, 3)]")
}
12 changes: 12 additions & 0 deletions string/string.mbt
Original file line number Diff line number Diff line change
Expand Up @@ -116,6 +116,16 @@ pub fn to_array(self : String) -> Array[Char] {
}

///|
/// Returns an iterator over the Unicode characters in the string.
///
/// Note: This iterator yields Unicode characters, not Utf16 code units.
/// As a result, the count of characters returned by `iter().count()` may not be equal to the length of the string returned by `length()`.
///
/// ```
/// let s = "Hello, World!🤣";
/// assert_eq!(s.iter().count(), 14); // Unicode characters
/// assert_eq!(s.length(), 15); // Utf16 code units
/// ```
pub fn iter(self : String) -> Iter[Char] {
Iter::new(fn(yield_) {
let len = self.length()
Expand Down Expand Up @@ -162,6 +172,8 @@ pub fn iter2(self : String) -> Iter2[Int, Char] {
}

///|
/// Note: This method operates on Unicode characters, not Utf16 code units.
/// As a result, the count of characters passed to the folding function may not be equal to the length of the string.
pub fn fold[A](self : String, init~ : A, f : (A, Char) -> A) -> A {
let mut rv = init
for c in self {
Expand Down

0 comments on commit a854b26

Please sign in to comment.