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
2 changes: 2 additions & 0 deletions builtin/pkg.generated.mbti
Original file line number Diff line number Diff line change
Expand Up @@ -855,10 +855,12 @@ fn Bytes::of_string(String) -> Bytes
fn Bytes::to_unchecked_string(Bytes, offset? : Int, length? : Int) -> String

#alias("_[_]")
#deprecated
fn StringView::at(Self, Int) -> Int
fn StringView::char_length(Self) -> Int
fn StringView::char_length_eq(Self, Int) -> Bool
fn StringView::char_length_ge(Self, Int) -> Bool
fn StringView::code_unit_at(Self, Int) -> UInt16
fn StringView::contains(Self, Self) -> Bool
fn StringView::contains_any(Self, chars~ : Self) -> Bool
fn StringView::contains_char(Self, Char) -> Bool
Expand Down
21 changes: 12 additions & 9 deletions builtin/stringview.mbt
Original file line number Diff line number Diff line change
Expand Up @@ -31,23 +31,26 @@ fn StringView::make_view(str : String, start : Int, end : Int) -> StringView = "
/// Returns the charcode(UTF-16 code unit) at the given index.
///
/// This method has O(1) complexity.
///
/// # Example
///
/// ```mbt
/// let str = "Hello🤣🤣🤣"
/// let view = str.view(start_offset = str.offset_of_nth_char(1).unwrap(), end_offset = str.offset_of_nth_char(6).unwrap())
/// inspect(view[0].to_char(), content="Some('e')")
/// inspect(view[4], content="55358")
/// ```
#alias("_[_]")
#deprecated("Use `code_unit_at` instead which returns UInt16")
pub fn StringView::at(self : StringView, index : Int) -> Int {
guard index >= 0 && index < self.length() else {
abort("Index out of bounds")
}
self.str().unsafe_charcode_at(self.start() + index)
}

///|
/// Returns the UTF-16 code unit at the given index.
///
/// This method has O(1) complexity.
pub fn StringView::code_unit_at(self : StringView, index : Int) -> UInt16 {
guard index >= 0 && index < self.length() else {
abort("Index out of bounds")
}
self.str().code_unit_at(self.start() + index)
}

///|
/// Returns the length of the view.
///
Expand Down
19 changes: 19 additions & 0 deletions builtin/stringview_test.mbt
Original file line number Diff line number Diff line change
Expand Up @@ -30,3 +30,22 @@ test "StringView::suffixes" {
.collect()
@json.inspect(suffixes_no_empty, content=["a🤣b", "🤣b", "b"])
}

///|
test "code_unit_at" {
let s = "Hello, 世界!😀"
assert_true(s[:].code_unit_at(0) is 'H')
assert_true(s[:].code_unit_at(7) is '世')
assert_true(s[:].code_unit_at(8) is '界')
assert_true(s[:].code_unit_at(0) is ('A'..='Z'))
inspect(s[:].code_unit_at(0), content="72") // 'H'
inspect(s[:].code_unit_at(7), content="19990") // '世'
inspect(s[:].code_unit_at(8), content="30028") // '界'
inspect(s[:].code_unit_at(10), content="55357") // High surrogate of '😀'
inspect(s[:].code_unit_at(11), content="56832") // Low surrogate of '😀'
let view = s[7:] // "世界!😀"
inspect(view.code_unit_at(0), content="19990") // '世'
inspect(view.code_unit_at(1), content="30028") // '界'
inspect(view.code_unit_at(3), content="55357") // High surrogate of '😀'
inspect(view.code_unit_at(4), content="56832") // Low surrogate of '😀'
}
4 changes: 2 additions & 2 deletions encoding/utf16/encode.mbt
Original file line number Diff line number Diff line change
Expand Up @@ -38,15 +38,15 @@ pub fn encode(
arr[0] = 0xFE
arr[1] = 0xFF
for i in 0..<str.length() {
let code_unit = str[i]
let code_unit = str.code_unit_at(i)
arr[2 + i * 2] = (code_unit >> 8).to_byte()
arr[2 + i * 2 + 1] = (code_unit & 0xFF).to_byte()
}
arr.unsafe_reinterpret_as_bytes()
} else {
let arr = FixedArray::make(str.length() * 2, b'\x00')
for i in 0..<str.length() {
let code_unit = str[i]
let code_unit = str.code_unit_at(i)
arr[i * 2] = (code_unit >> 8).to_byte()
arr[i * 2 + 1] = (code_unit & 0xFF).to_byte()
}
Expand Down
4 changes: 2 additions & 2 deletions string/regex/internal/regexp/internal/vm/impl.mbt
Original file line number Diff line number Diff line change
Expand Up @@ -117,8 +117,8 @@ fn add_thread(
let assertion = match pred {
BeginText => sp == 0
EndText => sp == content.length()
BeginLine => sp == 0 || content[sp - 1] == '\n'
EndLine => sp == content.length() || content[sp] == '\n'
BeginLine => sp == 0 || content.code_unit_at(sp - 1) == '\n'
EndLine => sp == content.length() || content.code_unit_at(sp) == '\n'
WordBoundary =>
is_word_char_at(content, sp - 1) != is_word_char_at(content, sp)
NoWordBoundary =>
Expand Down
2 changes: 1 addition & 1 deletion string/view_test.mbt
Original file line number Diff line number Diff line change
Expand Up @@ -1044,7 +1044,7 @@ test "StringView add" {
test "panic view op_get out of bounds" {
let str = "Hello"
let view = str.view(start_offset=0, end_offset=5)
view[5] |> ignore
view.code_unit_at(5) |> ignore
}

// Added test to cover start index pointing to trailing surrogate
Expand Down